关于在使用Entity框架时将业务逻辑放在何处的困惑

obb*_*rus 49 c# entity-framework

我刚刚开始使用Entity框架,我对业务层中通常的类如何适应实体框架创建的实体感到困惑.

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

使用Entity Framework,如果您有一个名为Customer的表,Entity框架会创建一个名为Customer的实体,这就是我的困惑开始的地方,这个实体是否消除了业务层中对Customer的需求?因此,实质上通常在业务层中的所有字段和方法都在实体框架生成的实体中?或者,如果一个类仍然存在于名为CustomerBL的业务层中,那么它仍然包含完成计算,过滤所需的业务逻辑所需的字段和方法,并且仍然需要声明处理数据访问的EF DAL实例?

如果应该有一个业务类,在这种情况下是CustomerBL,另外还有一个问题,如果客户实体中创建的字段在CustomerBL中重新创建,或者应该在CustomerBL中声明Customer实体的实例,那么就会有不需要在2个位置声明字段?

Ger*_*old 25

与linq-to-sql相反,实体框架的设计考虑了数据模型和概念模型之间的分离.它支持继承,实体拆分,表拆分,复杂类型透明的多对多关联,所有这些都允许根据数据存储模型对域模型进行模拟,而不会受到太多限制.

代码优先方法允许使用POCO,其中所选属性可以映射到数据存储列.模型优先和数据库优先生成部分类,允许人们扩展生成的代码.与这些课程合作在很大程度上具有与POCO合作的外观和感觉.从版本5开始,当它DbContext成为默认API时,生成的类不再填充ObjectContextAPI的持久性相关代码.

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

持久性无知的另一个重要违反是linq-to-objects和linq-to-entities之间的大量差异.你不能忽视这样一个事实:你正在与一个完全不同的宇宙而不是内存中的物体.这被称为紧耦合或泄漏抽象.

但是......通常我很高兴使用代码优先模型生成的EF类或POCO作为域类.到目前为止,我从未见过从一个数据存储到另一个数据存储的无摩擦过渡,如果它发生的话.坚持无知是一种虚构.来自DAL的特性总是在该领域留下足迹.只有当您必须为不同的数据存储/模型编写代码或者预期存储/模型相对经常变化时,才能尽可能地减少这种占用空间或完全抽象出来.

另一个因素是可以提升EF类作为域类是当今许多应用程序具有多个层,其中(序列化)不同的视图模型或DTO被发送到客户端.在UI中使用域类几乎不符合要求.您也可以将EF类用作域,并让服务根据UI或服务使用者的要求丢弃专用模型和DTO.如果只是表现方面的话,另一个抽象层可能更多的是负担而不是祝福.

  • 格特,没有任何不尊重的意图,但你可以和我一起参加我的水平,或许可以让我知道你所说的内容如何适用于我原来的帖子中的例子,因为我并没有完全跟随你,因为毕竟我对你很新EF. (5认同)
  • 那个好老板!这一切归结为一个建议(我的意见):按原样使用EF类.哪个是`Customer`类,而不是额外的`CustomerBL`类.使用部分类可以使用业务逻辑扩展生成的类. (3认同)

Sla*_*uma 14

在我看来,使用POCO作为可以持久化的实体的重点是消除"数据库实体"和"业务实体"之间的区别."实体"应该是"业务实体",可以直接存储到数据存储并从数据存储加载,因此可以同时充当"数据库实体".通过使用POCO,业务实体与特定机制分离,以与数据库交互.

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

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

  • 您必须创建导航属性(引用或引用其他实体的集合)virtual以支持使用EF延迟加载
  • 您不能IEnumerable<T>用于必须持久化的集合.它必须是ICollection<T>或更衍生的类型.
  • 坚持private财产并不容易
  • charEF不支持该类型,如果要保留其值,则不能使用它
  • 和更多...

但是,在我看来,另外一组实体是一个额外的复杂层,如果上述限制对于您的项目而言过于紧张,那么这些复杂性应该是真正需要的.

YA2C(还有2美分:))

  • 我同意这一点,它也是ORM的基础机制,它"替换"数据层而不是实体本身.在MVC类型的应用程序中,我可以创建单独的ViewModel来表达不是根据需要从实体派生的特定信息.就像OP一样,我仍然觉得这很难导航. (3认同)

dut*_*tzu 5

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

EF生成的类是您的DAL,然后为BL创建一组补充类,您将拥有所需的结构(例如,可能以一对一的关系合并来自相关实体的数据),并处理其他业务逻辑问题(自定义验证,例如实现IDataErrorInfo以使其与WPF中的UI一起运行)并且还创建包含与实体类型相关的所有业务层方法的类,这些方法使用BL实例并转换为EF实体和从EF实体转换到BL对象.

因此,例如,您的数据库中有Customer.EF将生成一个Customer类,在BL中将有一个Customer(前缀,后缀等)类和一个CustomerLogic类.在BL Customer类中,您可以执行满足要求所需的任何操作,而无需篡改EF实体,而在CustomerLogic类中,您将拥有BL方法(加载最有价值的客户,使用额外数据保存客户等).

现在,这使您可以松散地耦合到数据源实现.过去(在WPF项目中)这让我受益的另一个例子是,您可以执行诸如实现IDataErrorInfo之类的操作并在CustomerBL类中实现验证逻辑,以便在将实体绑定到UI上的创建/编辑表单时您将受益于WPF提供的内置功能.

...我的2美分,我也很想知道什么是最佳做法或其他解决方案/观点是什么.


也许与此主题相关 - 代码优先与模型/数据库优先