我偶然发现了以下两篇文章First和Second,其中作者总结说ORM实体和域实体不应混淆。
我正好面对这个问题,因为我使用Code First方法使用EF 6.0进行编码。我使用POCO类作为EF中的实体以及我的域/业务对象。但我经常发现自己经常将属性定义为public或导航属性为virtual,因为EF Framework强迫我这样做。
我不知道该怎么做这两篇文章的底线?我是否真的应该为实体框架创建一个CustomerEF类,为我的域创建一个CustomerD。然后创建一个使用CustomerD的存储库将它映射到CustomerEF做一些查询,然后将收到的CustomerEF映射回CustomerD。我认为EF就是将我的域实体映射到数据。
所以请给我一些建议。我是否忽略了EF能够为我提供的重要事项?或者这是EF无法完全解决的问题?在后一种情况下,管理这个问题的好方法是什么?
答案 0 :(得分:67)
我同意这些帖子的一般想法。 ORM类模型首先是数据访问层的一部分(即使它由所谓的POCO组成)。如果持久性和业务逻辑(或任何其他问题)之间出现任何利益冲突,则应始终做出有利于持久性的决策。
但是,作为软件开发人员,我们总是要在纯粹主义和实用主义之间取得平衡。是否将持久性模型用作域模型取决于许多因素:
开发团队的规模/一致性。当整个团队知道属性可以仅仅因为ORM要求而公开,但不应该在所有地方设置,这可能不是什么大问题。如果每个人都知道(并且遵守)不在业务逻辑中使用ID属性,那么拥有ID可能不是什么大问题。分散,缺乏经验或没有纪律的团队可能需要更严格的代码隔离。
业务逻辑问题与持久性问题之间的重叠。当类模型坚持SOLID原则时,面向对象的设计会蓬勃发展。但这些原则并不一定与持久性问题相矛盾。我的意思是虽然关注点不同,但最终的要求可能非常相似。例如,这两个问题都可能需要有效的对象状态和正确的关联。
然而,可能存在一些用例,其中对象暂时需要处于绝对不应存储的状态。这可能是使用专用域类的原因。另一个原因可能是实体模型无法实现最佳责任细分。例如,业务流程“将客户列入黑名单”可能需要分散在如此多实体对象上的数据,以至于必须设计新的域类,以便封装数据和处理它们的方法。换句话说:通过实体执行此操作会违反Tell Don't Ask原则。
需要分层。例如,如果数据访问层面向不同的数据库供应商,则它可能必须由供应商特定的可互换部分组成(例如,考虑Oracle和Sql Server之间数据类型的细微差别或利用特定于供应商的功能)。使用持久性模型作为域模型可能会将特定于供应商的实现泄露到业务逻辑中。那真是太糟糕了。那里的数据访问层应该是一层。
(非常简单)数据量。创建对象需要时间和资源。当业务案例涉及“很多”对象时,构建实体对象和域对象可能过于昂贵。
所以我总是试图成为一个实用主义者。如果实体课做得不错,那就去吧。如果不匹配太大,请为业务逻辑的适当部分创建业务域。我不会盲目地遵循(任何)设计模式只是因为它是一个好的模式。与帖子中所说的相反,将实体模型映射到商业模型需要大量维护。当您发现自己创建了几乎与实体类完全相同的业务类时,是时候重新考虑您正在做的事情了。