我已经阅读了 DDD Evans,并且正在尝试使用 C# 和 Entity Framework 4.1 + LINQ 进行聚合根存储库设计。
但是,我担心发送到数据库的实际查询。我正在使用 SQL 2008 R2,并运行 SQL Profiler 来检查数据库响应 LINQ 代码所做的工作。
考虑一个包含 Person 和 EmailAddress 的简单 2 实体设计。一个人可以有零到多个电子邮件地址,一个电子邮件地址必须只有一个人。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)。