C# 使用实体框架时关于将业务逻辑放在哪里的困惑
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14343821/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Confusion about where to put business logic when using Entity framework
提问by obb-taurus
I've just started working with the Entity framework and I'm confused about how the classes normally in the business layer fit in with the entities that are created by the Entity Framework.
我刚刚开始使用实体框架,我对业务层中的类通常如何与实体框架创建的实体相适应感到困惑。
When working with classic ADO.NET, I would have a class called Customer for example and then another class called DALCustomer to handle database interaction, in this structure I would have put the code to do calculations, filtering and delcare an instance of the DAL withing Customer for saving, updating and deleting in the Customer class.
当使用经典的 ADO.NET 时,我会有一个名为 Customer 的类,然后另一个名为 DALCustomer 的类来处理数据库交互,在这种结构中,我将代码用于计算、过滤和删除 DAL 的实例Customer 用于在 Customer 类中保存、更新和删除。
With the Entity Framework, if you have a table called Customer, the Entity framework creates an entity called Customer and this is where my confusion begins, does this entity remove the need for a Customer in the business layer? So in essence all the fields and methods that normally go in the business layer go in the entity generated by the Entity Framework? Or should a class still exist in the business layer called CustomerBL for example, that still contains the fields and methods needed to accomplish the business logic required for calculations, filtering and still needs an instance of the EF DAL declared to handle data access?
使用实体框架,如果您有一个名为 Customer 的表,则实体框架会创建一个名为 Customer 的实体,这就是我的困惑开始的地方,这个实体是否消除了业务层中对 Customer 的需求?那么本质上,通常进入业务层的所有字段和方法都进入了实体框架生成的实体?还是应该在业务层中仍然存在一个名为 CustomerBL 的类,例如,它仍然包含完成计算、过滤所需的业务逻辑所需的字段和方法,并且仍然需要声明一个 EF DAL 的实例来处理数据访问?
If there should be a business class, in this case CustomerBL, one other question jumps to mind, should the fields that are created in the customer entity be recreated in CustomerBL or should an instance of the Customer entity be declared in CustomerBL so there would be no need to have the fields declared in 2 locations?
如果应该有一个业务类,在这种情况下 CustomerBL,另一个问题会跳到脑海中,是否应该在 CustomerBL 中重新创建在客户实体中创建的字段,或者是否应该在 CustomerBL 中声明 Customer 实体的一个实例,以便有不需要在 2 个位置声明字段?
回答by dutzu
I don't know if it's considered a good practice by others but personally this is how i handled this in the past:
我不知道其他人是否认为这是一个很好的做法,但我个人过去是这样处理的:
The classes generated by EF are your DAL, and then for BL create a complementary set of classes in which you will have the structure you require (like maybe merging data from related entities in a one to one relationship) and other business logic concerns are handled (custom validation like implementing IDataErrorInfo to make it play nice with the UI in WPF for instance) and also create classes that would contain all the business layer methods relating to a type of entity, that use the BL instances and convert to and from EF entities to the BL objects.
EF 生成的类是您的 DAL,然后为 BL 创建一组互补的类,您将在其中拥有所需的结构(例如可能以一对一关系合并来自相关实体的数据)并处理其他业务逻辑问题(自定义验证,例如实现 IDataErrorInfo 以使其与 WPF 中的 UI 配合良好)并创建包含与实体类型相关的所有业务层方法的类,这些方法使用 BL 实例并与 EF 实体相互转换到 BL 对象。
So, for instance, you have Customer in your db. EF will generate a class Customer, and in the BL there will be a Customer (prefix, suffix, etc.) class and a CustomerLogic class. In the BL Customer class you can do whatever is needed to satisfy requirements without having to tamper with the EF entities and in the CustomerLogic class you would have BL methods (load most valued customers, save customer with extra data, etc.).
因此,例如,您的数据库中有 Customer。EF会生成一个类Customer,BL中会有一个Customer(前缀、后缀等)类和一个CustomerLogic类。在 BL Customer 类中,您可以做任何需要满足需求的事情,而不必篡改 EF 实体,而在 CustomerLogic 类中,您将拥有 BL 方法(加载最有价值的客户,用额外的数据保存客户等)。
Now, this enables you to be loosely coupled to the datasource implementation. Another example of why this has benefited me in the past (in a WPF project) is that you can do stuff like implement IDataErrorInfo and implement validation logic in the CustomerBL classes so that when you bind the entity to a create/edit form on the UI you will benefit from the built in functionality provided by WPF.
现在,这使您能够与数据源实现松散耦合。过去(在 WPF 项目中)这使我受益的另一个示例是,您可以执行诸如实现 IDataErrorInfo 并在 CustomerBL 类中实现验证逻辑之类的操作,以便在将实体绑定到 UI 上的创建/编辑表单时您将受益于 WPF 提供的内置功能。
...My 2 cents, i am also curious to find out what is the best practice or what other solutions/points of view are.
...我的 2 美分,我也很想知道什么是最佳实践或其他解决方案/观点是什么。
Also perhaps related to this topic - Code-first vs Model/Database-first
也可能与此主题有关 -代码优先 vs 模型/数据库优先
回答by Gert Arnold
Entity framework was designed with separation between data model and conceptual model in mind. It supports inheritance, entity splitting(not EF core), table splitting, complex typesor owned types, and transparent many-to-many associations(not EF core), all of which allow molding the domain model to one's needs without being constrained too much by the data store model. EF core supports shadow properties which can be used to hide cross-cutting concerns from the exposed class model.
实体框架的设计考虑了数据模型和概念模型之间的分离。它支持继承、实体拆分(非 EF 核心)、表拆分、复杂类型或拥有类型,以及透明的多对多关联(非 EF 核心),所有这些都允许根据自己的需要塑造领域模型而不受约束很大程度上取决于数据存储模型。EF 核心支持阴影属性,可用于隐藏暴露的类模型中的横切关注点。
The code-first approach allows working with POCOs in which only a few properties are mapped to data store columns and others serve domain goals. Model-first and Database-first generate partial classes, allowing one to extend the generated code.
代码优先方法允许使用 POCO,其中只有少数属性映射到数据存储列,而其他属性则服务于域目标。模型优先和数据库优先生成部分类,允许扩展生成的代码。
Of course this separation of conceptual model and store model can only succeed to a certain extent. Some things work against this goal of persistence ignorance. For instance -
当然,这种概念模型和商店模型的分离只能在一定程度上成功。有些事情与坚持无知的目标背道而驰。例如 -
If lazy loading is desirable, it is necessary to declare navigation properties as
virtual
, so EF can override them in proxy types. Domain-driven design (DDD) would encourage usingvirtual
only when polymorphism is required.It is veryconvenient to have primitive foreign key properties (say,
ParentId
) accompanying the "real" associations (aParent
reference). Purists consider this a violation of DDD principles.The EF class model will is part of a data access layer and should primarily serve that goal. Therefore, it will contain many reciprocal relationships, in order to benefit from navigation properties as much as possible when writing LINQ queries. These mutual relationships are another violation of DDD principles.
There is a large number of differences between LINQ-to-objects and LINQ-to-entities. You just can't ignore the fact that you are LINQ-ing against a totally different universe than objects in memory. This is referred to as tight coupling, or leaky abstraction.
EF can only map concrete classes, no interfaces.
如果需要延迟加载,则需要将导航属性声明为
virtual
,以便 EF 可以在代理类型中覆盖它们。领域驱动设计 (DDD)virtual
仅在需要多态时才鼓励使用。这是非常有原始的外键的属性(比如说,便捷
ParentId
随行“真正的”协会(一)Parent
参考)。纯粹主义者认为这违反了 DDD 原则。EF 类模型将是数据访问层的一部分,主要服务于该目标。因此,它将包含许多相互关系,以便在编写 LINQ 查询时尽可能地从导航属性中受益。这些相互关系是另一种违反 DDD 原则的行为。
LINQ-to-objects 和 LINQ-to-entities 之间存在大量差异。您不能忽视这样一个事实,即您是针对与内存中的对象完全不同的宇宙进行 LINQ 操作的。这被称为紧耦合或泄漏抽象。
EF 只能映射具体的类,不能映射接口。
But then... generally I'm happy with using generated EF classes or POCOs from a code-first model as domain classes. So far, I've never seen a frictionless transition from one data store or ORM to another, if it happens at all. Persistence ignorance is a fiction. Idiosyncrasies from the DAL easily leave a footprint in the domain. Only when you have to code for different data stores/models or when stores/models are expected to change relatively often it pays off to minimize this footprint as much as possible or abstract it away completely.
但是……通常我很高兴使用代码优先模型中生成的 EF 类或 POCO 作为域类。到目前为止,我从未见过从一个数据存储或 ORM 到另一个的无摩擦转换,如果它发生的话。坚持无知是虚构的。来自 DAL 的特性很容易在域中留下足迹。只有当您必须为不同的数据存储/模型编码或当存储/模型预计会相对频繁地更改时,才可以尽可能地减少这种占用空间或将其完全抽象出来。
Another factor that may promote EF classes as domain classes is that many applications today have multiple tiers, where (serialized) different view models or DTOs are sent to a client. Using domain classes in UIs hardly ever fits the bill. You may as well use the EF class model as the domain and have services return dedicated models and DTOs as required by a UI or service consumers. Another abstraction layer may be more of a burden than a blessing, if only performance-wise.
另一个可能将 EF 类提升为域类的因素是,当今的许多应用程序都有多个层,其中(序列化的)不同的视图模型或 DTO 被发送到客户端。在 UI 中使用域类几乎不符合要求。您也可以使用 EF 类模型作为域,并让服务根据 UI 或服务使用者的要求返回专用模型和 DTO。如果只是在性能方面,另一个抽象层可能更多的是负担而不是祝福。
回答by Slauma
In my opinion the whole point of using POCOs as entities that can be persisted is to remove the distinction between "database entities" and "business entities". "Entities" are supposed to be "business entities" that directly can be persisted to and loaded from a data store and therefore act as "database entities" at the same time. By using POCOs the business entities are decoupled from the specific mechanism to interact with a database.
在我看来,使用 POCO 作为可以持久化的实体的全部意义在于消除“数据库实体”和“业务实体”之间的区别。“实体”应该是“业务实体”,可以直接持久化到数据存储并从数据存储加载,因此同时充当“数据库实体”。通过使用 POCO,业务实体从与数据库交互的特定机制中分离出来。
You can move the entities into a separate project - for example - that has no references to any EF assembly and yet use them in a database layer project to manage persistence.
您可以将实体移动到一个单独的项目中 - 例如 - 没有对任何 EF 程序集的引用,但在数据库层项目中使用它们来管理持久性。
This does not mean that you can design your business entities completely without having the requirements for EF in mind. There are limitations you need to know to avoid trouble when you come to the point to map the business entities to a database schema using EF, for instance:
这并不意味着您可以在不考虑 EF 要求的情况下完全设计您的业务实体。当您开始使用 EF 将业务实体映射到数据库模式时,您需要了解一些限制以避免麻烦,例如:
- You must make navigation properties (references or collections of references to other entities)
virtual
to support lazy loading with EF - You cannot use
IEnumerable<T>
for collections that have to be persisted. It must beICollection<T>
or a more derived type. - It's not easy to persist
private
properties - The type
char
is not supported by EF and you can't use it if you want to persist its values - and more...
- 您必须制作导航属性(对其他实体的引用或引用集合)
virtual
以支持使用 EF 进行延迟加载 - 您不能
IEnumerable<T>
用于必须持久化的集合。它必须是ICollection<T>
或更派生的类型。 - 持久化
private
属性并不容易 char
EF 不支持该类型,如果要保留其值,则不能使用它- 和更多...
But an additional set of entities is - in my opinion - an additional layer of complexity that should be justified to be really needed if the mentioned limitations are too tight for your project.
但是,在我看来,额外的一组实体是额外的复杂层,如果提到的限制对您的项目来说太紧,则应该证明确实需要它。
YA2C (Yet another 2 cents :))
YA2C(还有 2 美分 :))
回答by masterlopau
This topic maybe a bit old but this may help. Andras Nemes pointed out in his blog the concern of using DDD (domain driven design) over the technology driven design such as EF, MVC, etc.
这个话题可能有点旧,但这可能会有所帮助。Andras Nemes 在他的博客中指出了使用 DDD(领域驱动设计)而不是 EF、MVC 等技术驱动设计的担忧。
回答by user3866304
I used the business logic to write my methods and return the results in its created view like:
我使用业务逻辑来编写我的方法并在其创建的视图中返回结果,例如:
namespace Template.BusinessLogic
{
public interface IApplicantBusiness
{
List<Template.Model.ApplicantView> GetAllApplicants();
void InsertApplicant(Template.Model.ApplicantView applicant);
}
}