【发布时间】:2011-05-18 15:23:34
【问题描述】:
我读过 DDD Evans,并且正在尝试使用 C# 和 Entity Framework 4.1 + LINQ 进行聚合根存储库设计。
但是,我担心发送到数据库的实际查询。我正在使用 SQL 2008 R2,并运行 SQL Profiler 来检查数据库响应 LINQ 代码所做的工作。
考虑一个简单的 2 实体设计,其中包含 Person 和 EmailAddress。一个人可以有零到多个电子邮件地址,一个电子邮件地址必须只有一个人。 Person 是聚合根,因此不应有电子邮件地址的存储库。电子邮件地址应从个人存储库中选择(根据 DDD Evans)。
为了比较,我确实为电子邮件地址设置了一个临时存储库。以下代码行:
var emailString = "someone@somewhere.com";
var emailEntity = _tempEmailRepository.All.SingleOrDefault(e =>
e.Value.Equals(emailString, StringComparison.OrdinalIgnoreCase));
...根据分析器执行一个干净整洁的 SQL 查询:
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]
我可以使用以下代码从人员存储库中选择电子邮件:
var emailEntity = _personRepository.All.SelectMany(p => p.Emails)
.SingleOrDefault(e => e.Value.Equals(emailString,
StringComparison.OrdinalIgnoreCase))
这让我在运行时获得了相同的实体,但 SQL Profiler 中显示了不同的命令:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
FROM [dbo].[Person] AS [Extent1]
除了上述从 Person 中选择的查询之外,还有许多“RPC:Completed”事件,一个对应于 DB 中的每个 EmailAddress 行:
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
我的测试数据库在 dbo.EmailAddress 中有 14 行,并且有 14 个不同的 RPC:Completed 调用,每个调用都有不同的 @EntityKeyValue1 值。
我假设这对 SQL 性能不利,因为随着 dbo.EmailAddress 表获得更多行,将在 db 上调用更多这些 RPC。在 EF 4.1 + LINQ 中使用 DDD 聚合根存储库还有其他更好的方法吗?
更新:已解决
问题是 All 属性返回了 IEnumerable<TEntity>。在将其更改为IQueryable<TEntity> 之后,LINQ 开始介入并一次性选择了整个 Person + Emails。但是,在从 All 返回 IQueryable 之前,我必须链接 .Include(p => p.Emails)。
【问题讨论】:
-
你从
All属性返回什么? -
好问题。当我发布这个 All 时返回一个 IEnumerable
。将其更改为 IQueryable 并看到了不同之处。将发布更新。
标签: linq entity-framework-4.1 ddd-repositories