EF 5 y Table Value Functions

El soporte de TVF ha sido uno de los elementos más demandados dentro de los foros y listas de insiders al grupo de ADO.NET. A pesar de que teníamos en EDM pequeños trucos con lo que podríamos hacer funcionar esta característica en 4.0, aunque seguro que todos los que habéis jugado con EDM sabéis que no es muy buena idea andar tocando a mano el XML subyacente, por no decir que es de lo más viscoso con lo que puedas encontrarte, el convertir a estas UDF’s en ciudadanos de primer nivel parecía algo necesario que por suerte tenemos ya disponible de forma idéntica a como usamos procedimientos almacenados en la actualidad. Por supuesto, no voy a hacer una introducción a las TVF’s, seguro que ya hay mucho contenido en internet sobre el asunto, por lo que lo único que diremos es que a grosso modo los TVF aúnan lo bueno de las vistas, la composición, y lo bueno de los procedimientos, que pueden contener código procedural, permitiéndonos ya sobre EF mezclarlas con L2E y ESQL, que es lo que a nosotros nos dará más valor todavía. Con el fin de mostrar un pequeño ejemplo partiremos de una sencilla tabla en la que tenemos un índice full text ,el script de esta tabla es el siguiente:

 

SET ANSI_NULLS ON

GO

 

SET QUOTED_IDENTIFIER ON

GO

 

CREATE TABLE [dbo].[book](

    [id] [int] IDENTITY(1,1) NOT NULL,

    [name] [nvarchar](200) NOT NULL,

    [description] [nvarchar](max) NOT NULL,

    [isbn] [nvarchar](15) NOT NULL,

 CONSTRAINT [PK_book] PRIMARY KEY CLUSTERED 

(

    [id] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

 

GO

Acto seguido, crearemos una también sencilla TVF que haga una query  usando full text sobre la tabla anterior, por ejemplo, la siguiente udf.

 

CREATE FUNCTION [dbo].[BookFullText]

(@text NVARCHAR(4000))

RETURNS TABLE

RETURN

 SELECT isbn,name

 FROM dbo.book

 WHERE CONTAINS([description], @text);

 

 

Una vez hecho el trabajo, como comentábamos anteriormente, ya podemos mapear esta TVF dentro de nuestros modelos EDM igual que un procedimiento almacenado, para esto, sino sabe como, le recomiendo seguir la siguiente guía, y utilizarlos de diversas maneras, aunque mezclándolas con nuestras L2E es como se ve mejor el porque de la importancia de esta mejora.

A continuación se puede ver el uso de la función anterior:

 

var result = from author in unitOfWork.Authors

              join books in unitOfWork.BookFullText("framework")

              on author.id equals books.Value

              select author;

 

Que produciría la siguiente traza TSQL

 

exec sp_executesql N'SELECT 

[Extent1].[id] AS [id], 

[Extent1].[name] AS [name]

FROM  [dbo].[Author] AS [Extent1]

INNER JOIN [dbo].[BookFullText](@text) AS [Extent2] ON [Extent1].[id] = [Extent2].[id]',N'@text nvarchar(4000)',@text=N'framework'

 

 

Bueno, aquí termina esta entrada…

 

Saludos

Unai

Domain Events y Agregados

Hace ya mucho tiempo que tenía ganas de escribir sobre este tema, por desgracia, entre unas cosas y otras no he tenido demasiadas oportunidades, pero bueno, por aquí empezamos el tema, el cual podremos continuar si veo la oportunidad. Los eventos, dentro de los modelos de dominio no es algo nuevo, de hecho ya hace mucho tiempo que hay definiciones y ejemplos de implementaciones como por ejemplo los de Udi Dahan, aquí y aquí, sin embargo, con la corriente de CQRS y sus elementos colaterales, se han puesto todavía más en boca, aunque en realidad en ocasiones hablamos sobre conceptos y terminologías diferentes. De lo que nosotros hablaremos es únicamente de eventos en dominio y de cuales son las ventajas que estos nos proporcionan. Lógicamente, antes de nada, vamos a poner algunas características que nos permitan entender que es un evento:

  • Siempre definen algo que ha ocurrido, el pasado.
  • Puesto que definen algo que ha ocurrido, estos no pueden modificarse, es decir, son inmutables aunque contienen información del hecho, parámetros por ejemplo.

Los eventos nos permiten comunicar agregados, por ejemplo que una “transacción” ha ocurrido, sin necesidad de romper los límites de consistencia entre el cluster de entidades que forma un agregado. El tratamiento de eventos simplifica mucho ciertos procesos puesto que nos permiten una orientación más naturar que el trabajo “procedimental” que haríamos con la ausencia de estos. Tal y como comentábamos en el primer párrafo hay muchos ejemplos de implementaciones, tanto de las guías de estas corrientes como en muchos fragmentos de código existentes que seguramente podrá revisar, nosotros, en este post haremos algo muy sencillo con caracter ilustrativo más que con fines de ejemplo de implementación.

El siguiente fragmento podría considerarse como un evento, que notifica que un usuario ha sido bloqueado, fíjese en el caracter de pasado y en la inmutabilidad del mismo.

 

public class TheUserIsLocked

{

    string _email;

    public string Email

    {

        get

        {

            return _email;

        }

    }

 

    int _userId;

    public int UserId

    {

        get

        {

            return _userId;

        }

    }

 

    public TheUserIsLocked(int userId, string email)

    {

        this._userId = userId;

        this._email = email;

    }

}

 

Ahora, dentro del proceso con un agregado, se puede notificar este hecho a cualquier parte interesada por ejemplo utilizando alguna implementación de un publicador.

 

var userIsLockedEvent = new TheUserIsLocked(1, "unai@plainconcepts.com");

 

_eventPublisher.Publish(userIsLockedEvent);

 

Ahora, cualquiera de las partes interesadas ( consumidores ) podrían escribir un manejador para este suceso que por suspuesto, puede ( suele ) necesitar el trabajo con otro agregado,

public class TheUserIsLockedEventConsumer

    :IConsumer<TheUserIsLocked>

{

    public void Handle(TheUserIsLocked @event)

    {

        //TODO

    }

 

 

Aunque esto, ha sido un ejemplo sencillo, repito que con fines únicamente ilustrativos, puede dar buena idea de los beneficios que los eventos de dominio pueden aportarnos a la hora de resolver un problema.

 

Saludos

Unai

EF 5 y la re-generación de esquema

En este mismo blog ya he hablado mucho con respecto a las migraciones y los inicializadores de Entity Framework,  (aquí, aquí o aquí son algunas entradas ), así  como su evolución desde las betas hasta la version 4.3.1 que tenemos en la actualidad como última version final. Pués bien, EF 5 incluye un pequeño cambio con respecto al trabajo con las bases de datos subyacentes que me parece muy sutil pero importante. Desde la llegada de las migraciones el proceso de comprobación de las bases de datos de trabajo se realizaba, una vez por appdomain, utilizando una tabla llamada _MigrationHistory establecida como tabla de sistema, en esta tabla, además de otros datos que no vienen  a cuento,encontrabamos el hash del modelo con el que puede trabajar esa base de datos, si el hash del modelo y el almacenado en la base de datos coincide entonces estamos correctos para realizar el trabajo. En el caso de que no coincida, entonces dependera de nuestros inicializadores el saber que pasa, por ejemplo, si tenemos establecido MigrateDatabaseToLatestVersion podremos actualizar nuestra base de datos en el proceso de inicializacion. Aunque parezca que con esto tenemos suficiente, hay un caso que lo rompe, por ejemplo, cuando tenemos una base de datos que no ha sido creada por nosotros, por ejemplo, con alguno proceso de deployment automático o bien por un tercero sobre el que no tenemos control. En este casuística se nos da la situación de que la base de datos existe pero la tabla de migraciones no existe o incluso alguna de las tablas ( o ninguna ) de nuestro esquema de trabajo tampoco tendrían por que estar.

Si ponemos a funcionar nuestra aplicación basada en EF 4.X en estas condiciones, la misma, miserablemente nos dará una excepción como la siguiente:

 

“{"Invalid object name ‘XXX’."}”

Aunque parezca una estupidez, este casuística puede ser habitual si hablamos de hosters que ya nos proporcionan catálogos de base de datos pero sin esquema o incluso si queremos trabajar con alguna base de datos existentie como por ejemplo algun proveedor de roles, profile etc… Por suerte, en EF 5 este problema se ha resuelto y como podeis ver en las trazas de Intellitrace de las siguientes laterales se ha resuelto porque previo al proceso de trabajo con la base de datos se hace una revisión de la información de las vistas del sistema INFORMATION_SCHEMA. En función del resultado de las consultas a estas vistas se realizan las operaciones de creación, si es necesario, tanto de las tablas de esquema como de la tabla de sistema _MigrationHistory con lo que ya podremos trabajar tranquilamente.

 

Output

 

Untitled

 

Bueno, aquí acaba esta pequeña entrada, ya llevaba un tiempo sin escribir, la suerte del trabajo y que por estas fechas uno siempre suele estar atareado intentando sacar más libros a la luz, para no variar, este último también sobre EF, pero de una forma diferente a los anteriores que espero os guste un poco más.

Saludos

Unai