我正试图为我的应用编写一些业务逻辑。我的应用程序的核心是来自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)将该逻辑放在其他类中,将实体作为函数参数。
对此有哪些好的常见做法?
答案 0 :(得分:7)
问题在于你混合了两种相反的设计:DDD和贫血模型。
如果您使用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