我应该在EF 4.1 + LINQ中使用DDD聚合根存储库吗?

| 我已经读过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 \”事件,对于数据库中的每个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表获得更多的行,将在数据库上调用更多的RPC \。是否还有另一种更好的方法将DD 4.1聚合根存储库与EF 4.1 + LINQ一起使用? 更新:已解决 问题在于All属性返回了
IEnumerable<TEntity>
。将其更改为
IQueryable<TEntity>
之后,LINQ参与进来,一口气选择了整个“人+电子邮件”。但是,在从All返回IQueryable之前,我必须链接.Include(p => p.Emails)。     
已邀请:
考虑到现代ORM已经给您的抽象级别,我个人建议不要在您和数据库之间添加额外的抽象层。除了重新设计轮子之外,您还会发现直接在服务层中使用所选的ORM将为您提供对查询,提取和缓存策略的更细粒度的控制。 对于反对将规范/存储库与现代ORM结合使用的其他各种论点,Ayende的系列《罪孽之祸》是一个很好的资源,尤其是考虑到LINQ已经有效地提供了您可能需要的几乎所有东西。 我在过去的项目中采用了“ DDD”的方法(用引号引起来,因为它与我当时对DDD的理解有关)。事后看来,我意识到在公开辩论中DDD经常被简化为应用这些模式是一种耻辱。我陷入了陷阱,希望我能帮助其他人避免这种情况。 存储库和规范是基础结构模式。基础设施是服务于目的,而不是目的本身。在基础架构方面,我主张严格应用重用抽象原理。为了提供一个简短的摘要,RAP表示,只有在两个以上的使用者将使用抽象并且该抽象的附加层实际上实现了某些行为的情况下,才应引入抽象。如果仅引入抽象来使您与某些事物(例如ORM)分离,请务必小心,最终您可能会得到泄漏的抽象。 DDD的全部目的是使您的域模型与基础架构保持分离,并使域模型尽可能具有表现力。没有证据表明,不使用存储库是无法实现的。存储库只是用来隐藏数据访问的详细信息,而ORM已经这样做了。 (顺便说一句,考虑到DDD书的年代,我认为当时的ORM并不常见。)现在,存储库可能对强制执行聚合根等有用。但是,我认为应该通过在“读”操作(查询)和“写”操作(命令)之间进行明确区分来解决。仅对于后者而言,域模型应该是相关的,查询通常可以通过量身定制(且更灵活)的模型(例如DTO或匿名对象)更好地服务。 规格的情况与此类似。规范的预期目的是相似的。它们的功能在于构建用于查询对象的领域特定语言的元素。随着LINQ的出现,提供用于组合这些元素的通用规范模式的许多“胶水”已经过时了。提示:看一下Predicate Builder(<50行C#),您可能需要实现规范。 总结一下这一篇冗长的文章(希望不要过于混乱,我希望稍后再重述): 不要为基础架构发怒,随您所愿建立基础架构。 将您的域模型用于特定于域的行为,而不是用于支持您的视图。 专注于DDD的更重要部分:使用聚合根,建立通用语言,确保与业务专家的良好沟通。     

要回复问题请先登录注册