在需要依赖项时,如何/在何处将业务逻辑放入EF实体?

时间:2014-06-05 09:43:08

标签: .net entity-framework architecture dependency-injection domain-driven-design

我正试图为我的应用编写一些业务逻辑。我的应用程序的核心是来自Database First模型的EF生成实体。我已经从.edmx部分分离了生成的类(.tt文件)。

我想找到放置业务逻辑的最佳位置,但问题是,业务逻辑需要一些复杂的依赖,例如,需要记录,调用一些WebService,或者使纯SQL调用DB。 正因为如此,我不能只使用new()内部函数并创建硬依赖,但我想以某种方式从它们中抽象出,遵循DI原则。

public class Person
{
    public Person(IDbCaller dbCaller, IWebServiceCaller webServiceCaller) { }
}

我的第一个赌注是使用扩展EF类的部分类。

但在阅读了一些文章后,我现在认为将依赖注入EF类并不是一个好主意:

Why not use an IoC container to resolve dependencies for entities/business objects?

http://lostechies.com/jimmybogard/2010/04/14/injecting-services-into-entities/

那么,我应该把这个逻辑放在哪里?我同意,对EF实体的依赖性很差,但我真的找不到解决方案。逻辑需要在某个地方。 我看到一些选项/问题:

1)在Service层中放置业务逻辑(需要依赖关系)。这可能导致贫血领域模型,但是服务层可能是这种逻辑的正确位置,需要依赖?

2)创建一些king或Wrapper / Factory类,每次查询返回实体时我都需要调用它,所以我可以用业务逻辑包装实体。

3)将该逻辑放在其他类中,将实体作为函数参数。

对此有哪些好的常见做法?

1 个答案:

答案 0 :(得分:7)

问题在于你混合了两种相反的设计:DDD和贫血模型。

  • DDD:就业务逻辑而言,没有依赖关系,因为对象本身就是必须实现它的东西
  • 贫血模型:这是使用EF的常用方法。对象是POCO:Fowler说“袋子的属性设置者和吸气剂”,并认为它是反模式。所有逻辑都在接收实体的服务中实现,并根据业务规则进行更改

如果您使用DDD

应用程序中的类必须是域对象(实体和值对象)。您必须实现它们,而不考虑它们将如何存储在数据库(或您使用的任何后端)中。完成域对象设计后,您将实现一个满足域对象持久性需求的EF模型。因此,在许多情况下,域对象(实体和值对象)与EF实体之间不会直接映射。

即。在此实现中,您的域对象必须在某个时刻存储数据。而且你必须实现支持存储这些数据的EF模型。

对于依赖项,在这种情况下,它们将位于您的域对象中,而不是在您的EF实体中。然后,您可以使用常用模式(Factory,DI)来创建域模型。可能其中一个依赖项是使用EF实现的存储库。

如果您使用贫血模型

首先,我必须说有很多这种成功的实现,即使Fowler说这是一种反模式。我不会同意或不同意福勒,但我必须暴露事实。

如果使用贫血模型实现应用程序,则可以从设计EF(贫血)模型开始,然后在服务类中实现所有业务逻辑。

最大的错误

贫血模型通常是以数据为中心的设计的结果。用福勒的话来说:我不知道为什么这种反模式如此普遍。我怀疑这是因为许多人没有真正使用适当的域模型,特别是如果他们来自数据背景。所以,如果你开始这样做:我的应用程序的核心是来自Database First模型的EF生成实体。您将无法实现纯DDD(you can read this article to understand why

回答你的意见:

1)这是一个贫血模型

2)您期望从存储数据到域对象的直接映射。您收到一个实体并希望为其添加功能。不!您的域对象必须使用EF来请求持久化数据,而不是反过来!

3)这又是1)

你会发现这篇文章非常有趣:The Anaemic Domain Model is no Anti-Pattern, it’s a SOLID design及其反驳:Rich Domain Is SOLID , Anaemic Domain Is An Anti Pattern