He leído DDD Evans y estoy experimentando con un diseño agregado de repositorio raíz usando C# y Entity Framework 4.1 + LINQ.¿Debo usar repositorios raíz agregados DDD con EF 4.1 + LINQ?
Sin embargo, me preocupan las consultas reales que se envían al DB. Estoy usando SQL 2008 R2 y ejecutando SQL Profiler para examinar lo que está haciendo el DB en respuesta al código LINQ.
Considere un diseño simple de 2 entidades con Person y EmailAddress. Una Persona puede tener cero a muchos EmailAddresses, y una EmailAddress debe tener exactamente una Persona. Person es la raíz agregada, por lo que no debe haber un repositorio para las direcciones de correo electrónico. Las direcciones de correo electrónico deben seleccionarse del repositorio de personas (según DDD Evans).
Para la comparación, tengo un repositorio temporal configurado para direcciones de correo electrónico. La siguiente línea de código:
var emailString = "[email protected]";
var emailEntity = _tempEmailRepository.All.SingleOrDefault(e =>
e.Value.Equals(emailString, StringComparison.OrdinalIgnoreCase));
... ejecuta una consulta SQL agradable limpio de acuerdo con el perfilador:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Value] AS [Value],
[Extent1].[IsDefault] AS [IsDefault],
[Extent1].[IsConfirmed] AS [IsConfirmed],
FROM [dbo].[EmailAddress] AS [Extent1]
puedo seleccionar el correo electrónico fuera del depósito de persona, con el siguiente código:
var emailEntity = _personRepository.All.SelectMany(p => p.Emails)
.SingleOrDefault(e => e.Value.Equals(emailString,
StringComparison.OrdinalIgnoreCase))
Esto me pone la misma entidad en tiempo de ejecución, pero con diferentes comandos a aparecer en el Analizador de SQL:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
FROM [dbo].[Person] AS [Extent1]
Además de la consulta anterior que selecciona de una persona, hay una serie de "RPC: completadas" eventos, uno para cada fila EmailAddress en el PP:
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Value] AS [Value],
[Extent1].[IsDefault] AS [IsDefault],
[Extent1].[IsConfirmed] AS [IsConfirmed],
FROM [dbo].[EmailAddress] AS [Extent1]
WHERE [Extent1].[PersonId] =
@EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Value] AS [Value],
[Extent1].[IsDefault] AS [IsDefault],
[Extent1].[IsConfirmed] AS [IsConfirmed],
FROM [dbo].[EmailAddress] AS [Extent1]
WHERE [Extent1].[PersonId] =
@EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=2
Mi db prueba tiene 14 filas en dbo.EmailAddress, y hay 14 RPC diferentes: llamadas completadas, cada una con un valor @ EntityKeyValue1 diferente.
Supongo que esto es malo para el rendimiento de SQL, ya que como la tabla dbo.EmailAddress obtiene más filas, se invocarán más de estas RPC en la base de datos. ¿Hay algún otro enfoque mejor para usar los repositorios raíz agregados DDD con EF 4.1 + LINQ?
Actualización: Resuelto
El problema era que el Toda la propiedad se devuelve un IEnumerable<TEntity>
. Después de que esto se cambió a IQueryable<TEntity>
, LINQ inició y seleccionó toda la Persona + Correos electrónicos en una sola toma. Sin embargo, tuve que encadenar. Incluir (p => p.Emails) antes de devolver IQueryable de All.
¿Qué devuelves de la propiedad 'All'? –
Buena pregunta. Cuando publiqué todo, todo devolvía un IEnumerable. Lo cambió a IQueryable y notó la diferencia. Publicará la actualización. –
danludwig