在使用entity framework时,对于放置业务逻辑的位置感到困惑

我刚刚开始使用Entity框架,对于通常在业务层中的类如何与由Entity Framework创build的实体相适应,我感到困惑。

当使用传统的ADO.NET时,我将有一个名为Customer的类,然后是另一个名为DALCustomer的类来处理数据库交互,在这个结构中,我将把代码进行计算,过滤和删除DAL的一个实例客户在客户类中保存,更新和删除。

使用entity framework,如果您有一个名为Customer的表,Entity框架将创build一个名为Customer的实体,这是我开始混淆的地方,这个实体是否会在业务层中删除对Customer的需求? 所以实质上所有通常在业务层中进行的字段和方法都进入entity framework生成的实体中? 或者,如果一个类仍然存在于名为CustomerBL的业务层中,那么它仍然包含完成计算所需的业务逻辑所需的字段和方法,并且仍然需要一个EF DAL实例来声明处理数据访问?

如果应该有一个业务类,在这种情况下CustomerBL,另一个问题跳转,顾客实体中创build的字段应在CustomerBL中重新创build,或者如果客户实体的一个实例在CustomerBL中声明,所以会有没有必要在两个地方声明字段?

与linq-to-sql相反,entity framework是在数据模型和概念模型之间进行分离devise的。 它支持inheritance , 实体分割 , 表格分割 , 复杂types以及透明的多对多关联 ,所有这些都可以使领域模型满足需求,而不会受到数据存储模型的太多限制。

代码优先的方法允许使用可以将选定属性映射到数据存储列的POCO。 Model-first和Database-first生成部分类,允许扩展生成的代码。 与这些class级合作很大程度上与POCO合作的外观和感觉。 甚至从版本5开始,当DbContext成为默认API时,所生成的类不再被ObjectContext API的与持久性相关的代码填充。

当然,这种概念模型和商店模型的分离只能在一定程度上取得成功。 有些事情与持久性无知的这个目标有关。 例如,如果需要延迟加载,则必须将导航属性声明为virtual ,因此EF可以在代理types中覆盖它们。 具有原始外键属性(比如ParentId )伴随“真实”关联( Parent引用)是非常方便的。 纯粹主义者认为这是违反领域驱动的devise。

持续性无知的另一个重要的违反是在线对象和线对实体之间的大量差异 。 你不能忽视这样一个事实,即你正处在一个完全不同的宇宙中,而不是记忆中的物体。 这被称为紧耦合,或者抽象抽象 。

但是,然后…通常我很高兴使用从代码优先模型生成的EF类或POCO作为域类。 到目前为止,如果发生这种情况,我从来没有见过从一个数据存储区到另一个数据存储区的无摩擦过渡。 坚持无知是一种虚构。 来自DAL的特性总是在该领域留下足迹。 只有当你不得不为不同的数据存储器/模型编码时,或者当商店/模型预期会相对经常地改变时,它将尽可能地减less这种占用空间或者完全抽象出来。

另一个因素是,可能促进EF类的领域类是,今天的许多应用程序有多个层,其中(序列化)不同的视图模型或DTOs发送到客户端。 在用户界面中使用域名几乎不符合法案。 您也可以将EF类作为域使用,并根据UI或服务使用者的要求提供专用模型和DTO。 如果只是在性能方面,另一个抽象层可能比祝福更重要。

在我看来,使用POCO作为可持续实体的重点在于消除“数据库实体”和“商业实体”之间的区别。 “实体”被认为是“商业实体”,可以直接从数据存储中持久存储和加载,因此可以同时充当“数据库实体”。 通过使用POCO,业务实体与特定机制分离,与数据库进行交互。

您可以将这些实体移动到一个单独的项目中,例如,它没有对任何EF程序集的引用,而是在数据库层项目中使用它们来pipe理持久性。

这并不意味着您可以完全devise您的业务实体,而不必考虑EF的要求。 为了避免麻烦,在使用EF映射业务实体到数据库模式时需要了解一些限制,例如:

  • 您必须将导航属性(对其他实体的引用或对引用的集合)设置为virtual以支持使用EF进行延迟加载
  • 您不能使用IEnumerable<T>作为必须持久化的集合。 它必须是ICollection<T>或更多派生types。
  • 坚持private财产并不容易
  • chartypes不受EF支持,如果要保留其值,则不能使用它
  • 和更多…

但是,在我看来,另外一组实体是额外的一层复杂性,如果上述限制对于您的项目来说过于紧张的话,那么这个复杂性应该是合理的。

YA2C(还有2分:) :))

我不知道这是否被他人认为是好的做法,但是我个人认为这是我过去的处理方式:

EF生成的类是你的DAL,然后为BL创build一个互补的类集,在这个类中你将拥有你所需要的结构(比如也许把相关实体的数据合并成一对一的关系),并处理其他的业务逻辑问题(自定义validation,如实现IDataErrorInfo,使其与WPF中的用户界面良好玩),并创build类将包含所有业务层方法有关的实体types,使用BL实例,并从EF实体转换和到BL对象。

所以,例如,你有你的数据库中的客户。 EF将生成一个Customer类,在BL中将有一个Customer(前缀,后缀等)类和一个CustomerLogic类。 在BL客户类中,您可以做任何需要的来满足需求,而不必篡改EF实体,在CustomerLogic类中您将拥有BL方法(加载最有价值的客户,为客户节省额外的数据等)。

现在,这使您可以松散地耦合到数据源实现。 另一个为什么这使得我在过去受益(WPF项目)的例子是,你可以做一些东西,如实现IDataErrorInfo,并在CustomerBL类中实现validation逻辑,以便当你将实体绑定到UI上的创build/编辑表单您将受益于WPF提供的内置function。

…我的2美分,我也很好奇,找出什么是最好的做法或其他解决scheme/观点是什么。


也可能与此主题相关 – “先优先”与“模型/数据库优先”

这个话题可能有点老,但这可能有帮助。 安德拉斯·内梅斯(Andras Nemes)在他的博客中指出,在EF,MVC等技术驱动的devise中使用DDD(域驱动devise)的担忧。

http://dotnetcodr.com/2013/09/12/a-model-net-web-service-based-on-domain-driven-design-part-1-introduction/

我使用业务逻辑来编写我的方法,并将结果返回到创build的视图中,如下所示:

 namespace Template.BusinessLogic { public interface IApplicantBusiness { List<Template.Model.ApplicantView> GetAllApplicants(); void InsertApplicant(Template.Model.ApplicantView applicant); } }