C# 业务逻辑层和数据访问层:循环依赖
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/458098/
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
Business Logic Layer and Data Access layer: circular dependency
提问by
I'm having a little Architecture problem. In my project I have a Business Logic Layer (BLL) that contains all my business rules, models and OO API for the interface. Each object has static methods like getById that return an instance of said object. Each object also has methods like save and, delete. This is very straightforward OO code.
我有一点架构问题。在我的项目中,我有一个业务逻辑层 (BLL),其中包含我所有的业务规则、模型和接口的 OO API。每个对象都有像 getById 这样的静态方法,它们返回该对象的一个实例。每个对象还具有保存和删除等方法。这是非常简单的 OO 代码。
Now I have a DataAccess layer (DAL), contained in a separate namespace, for each BLL object I have a DataClass or “Repository” which executes the getById and save commands. So in a way, the BLL save and getById methods are a thin layer around the DataClass methods.
现在我有一个数据访问层 (DAL),包含在一个单独的命名空间中,对于每个 BLL 对象,我都有一个数据类或“存储库”,它执行 getById 和保存命令。所以在某种程度上,BLL save 和 getById 方法是围绕 DataClass 方法的一个薄层。
public static NewsItem GetByID(int id)
{
return DataFactory.GetNewsItemRepository().GetNewsItemById(id);
}
In order for the DataClasses to return BLL objects, they need to know the BLL. so now we have:
为了让 DataClasses 返回 BLL 对象,它们需要知道 BLL。所以现在我们有:
GUI ---> BLL <---->DAL
GUI ---> BLL <----> DAL
The DataFactory only returns objects that implement an Interface, so I can hide implementation details like “OracleNewsItemRepository”.
DataFactory 只返回实现接口的对象,因此我可以隐藏“OracleNewsItemRepository”之类的实现细节。
But now for the thing that has been bugging me ever since I started Object Oriented programming. In my current solution, both BLL and the DAL need to know each other. This is a Circular Dependency, and it is best practice to avoid circular dependencies. Also I only want to expose the interfaces (and my DataFactory) and not my classes. This can be done by placing the DAL layer in a separate Assembly. Which would make sense. However, Visual Studio does not allow two Assemblies to refer eachother. Another question about this: C# internal access modifiers
但是现在,自从我开始面向对象编程以来一直困扰着我的事情。在我当前的解决方案中,BLL 和 DAL 都需要相互了解。这是一个循环依赖,最好避免循环依赖。此外,我只想公开接口(和我的 DataFactory)而不是我的类。这可以通过将 DAL 层放置在单独的程序集中来完成。这是有道理的。但是,Visual Studio 不允许两个程序集相互引用。关于此的另一个问题:C# 内部访问修饰符
Somehow I think I got my whole data access pattern wrong. It feels like I am convoluting the ActiveRecord pattern with other stuff like DataMappers. I have spent a lot of time on Martin Fowler's site, but those patterns are described very generic and are illustrated by a very abstract UML diagram.
不知何故,我认为我的整个数据访问模式都错了。感觉就像我正在将 ActiveRecord 模式与 DataMappers 之类的其他东西进行卷积。我在 Martin Fowler 的网站上花了很多时间,但是这些模式被描述得非常通用,并用一个非常抽象的 UML 图来说明。
They don't solve my problem. Maybe I'm a bit anal, and there is no such thing as a “perfect data access pattern”. And what I do now doesn't seem terribly wrong. But how I do things now, seems off…
他们没有解决我的问题。也许我有点肛门,没有“完美的数据访问模式”这样的东西。我现在所做的似乎并没有错。但我现在做事的方式,似乎不对劲……
Any ideas?
有任何想法吗?
采纳答案by Craig Wilson
I think your data access pattern is fine. What you are not doing is coupling your BLL to the OracleDAL. You are coupling to the DAL interfaces. A certain bit of coupling is absolutely required or you could never get anything done.
我认为您的数据访问模式很好。您没有做的是将您的 BLL 耦合到 OracleDAL。您正在耦合到 DAL 接口。一定程度的耦合是绝对需要的,否则您将永远无法完成任何事情。
I assume that your DataFactory and the INewsItemRepository classes exist outside your DAL Layer. The following is an example of how my solutions are organized. I don't use ActiveRecord, so this may not suit you perfectly.
我假设您的 DataFactory 和 INewsItemRepository 类存在于您的 DAL 层之外。以下是我的解决方案组织方式的示例。我不使用 ActiveRecord,所以这可能不适合你。
Core (Project) Domain Business Entities Data Repository Interfaces **Your DataFactory** OracleData (Project) Data Oracle Repository Implementations SqlData (Project) Data Sql Repository Implementations UI (Project)
Hope this helps.
希望这可以帮助。
回答by ng5000
In my opinion:
在我看来:
The Data Access Layer (DAL) should operate on POCOs (Plain old CLR objects) using operations such as: SaveNewsItem ( NewsItemDAO newsItemDAO )
. The POCOs are your DAOs (Data Access Objects).
数据访问层(DAL)应使用操作上波苏斯(普通老式CLR对象)进行操作,例如:SaveNewsItem ( NewsItemDAO newsItemDAO )
。POCO 是您的 DAO(数据访问对象)。
The Business Layer should contain the logic to convert a Data Access Object (DAO) into a rich business object, which is probably just the DAO plus some operations as well as any decoration/enrichment.
业务层应该包含将数据访问对象 (DAO) 转换为丰富的业务对象的逻辑,这可能只是 DAO 加上一些操作以及任何装饰/丰富。
The DAL should have no knowledge at all about the Business Logic Layer. It should, in theory, be able to be called from any client. For example, what if you wanted to seperate the DAL from the application and deploy it as a seperate service exposing itself via WCF?
DAL 应该对业务逻辑层一无所知。从理论上讲,它应该能够从任何客户端调用。例如,如果您想将 DAL 与应用程序分开并将其部署为通过 WCF 公开自身的单独服务,该怎么办?
As mentioned, the DAL operations, e.g. SaveNewsItem should be be accessed by the BO via interfaces, perhaps via dependency injection/IoC.
如前所述,BO 应该通过接口访问 DAL 操作,例如 SaveNewsItem,可能通过依赖注入/IoC。
回答by user53564
You can use interfaces/dependency injection to solve your problem.
您可以使用接口/依赖注入来解决您的问题。
Your business layer (BL) contains the data access (DA) interfaces that the (possibly more than one) DAL need to implement. The DAL projects have project references to BL so that they can spit out business objects (BOs) and implement the DA interfaces.
您的业务层 (BL) 包含(可能不止一个)DAL 需要实现的数据访问 (DA) 接口。DAL 项目具有对 BL 的项目引用,以便它们可以吐出业务对象 (BO) 并实现 DA 接口。
Your BOs can call DataFactory, which can instantiate a DA object via dependency injection or reflection.
您的 BO 可以调用 DataFactory,它可以通过依赖注入或反射来实例化一个 DA 对象。
I have used this pattern in many of our applications here at work (both web-based and smart-client), and it works beautifully.
我已经在我们工作中的许多应用程序(基于 Web 和智能客户端)中使用了这种模式,并且它工作得很好。
回答by Trent
Just to be clear, I like to think of a Business Model and Business Logic as two separate layers. Your business model are your POCOs (Plain old CLR objects). Your business logic layer would be responsible for performing validations, transactions, etc using both your business model and an interface to your DAL that could be wired up a number of ways (Spring, Castle, or your own home grown IoC container).
明确地说,我喜欢将业务模型和业务逻辑视为两个独立的层。您的业务模型是您的 POCO(普通的旧 CLR 对象)。您的业务逻辑层将负责使用您的业务模型和 DAL 接口执行验证、事务等,该接口可以通过多种方式(Spring、Castle 或您自己的 IoC 容器)连接。
A good way to achieve zero dependencies in your DAL with your business model is to use an already built object relation mapping framework (ORM) such as NHibernate (a shameless plug for my favorite ORM framework).
在 DAL 中实现与业务模型零依赖关系的一个好方法是使用已经构建的对象关系映射框架 (ORM),例如 NHibernate(我最喜欢的 ORM 框架的无耻插件)。
回答by Abdullah BaMusa
DAL must be abstract, so it must contains only plain ADO.NET objects that interact with backend database e.g connection DataAdapter, DataReader and so on. With that at hand you can reference DAL in you Biz layer, and when it comes to your entities with a little abstraction you can solve all your problems, for example if you have customer class, you can make an abstaractoin customer class that implement the the basic operations to interact with DAL like save, update and retrieve data and in another class that inherits the abstraction class override the base class methods implementation to meet your Biz validation and so on.
DAL 必须是抽象的,因此它必须只包含与后端数据库交互的普通 ADO.NET 对象,例如连接 DataAdapter、DataReader 等。有了这个,你就可以在你的 Biz 层中引用 DAL,当涉及到你的实体时,你可以通过一些抽象来解决你所有的问题,例如,如果你有客户类,你可以创建一个 abstaractoin 客户类来实现与 DAL 交互的基本操作,如保存、更新和检索数据,并且在继承抽象类的另一个类中覆盖基类方法实现以满足您的 Biz 验证等。
回答by Owen
IceHeat, @Craig Wilson's example makes the most sense and its probablyderived from this article: http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx.
IceHeat,@Craig Wilson 的例子最有意义,它可能来自这篇文章:http: //www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx。
This is WELL worth a read and tackles domain driven development which resolves the issues you are facing here. Id recommend it to anyone, even if you don't give a monkeys about NHibernate its a great article.
这是非常值得一读的,它解决了领域驱动开发,它解决了您在这里面临的问题。我将它推荐给任何人,即使你不给猴子一个关于 NHibernate 的好文章。
回答by StackUnderflow
I would remove any Get() and Save() method from you BLL (Domain model).. here is what I would do
我会从你 BLL(域模型)中删除任何 Get() 和 Save() 方法..这就是我要做的
GUI will ask Repository to get domain object by id.. and once GUI has the domain object you could navigate it to reach other objects.. This way Domain layer does not need to know anything about repositories..
GUI 将要求 Repository 通过 id 获取域对象.. 一旦 GUI 拥有域对象,您就可以导航它以到达其他对象.. 这样域层不需要知道任何关于存储库的信息..
Inside repository you could return domain object that lazily load or completely load the object object graph.. this would depend on you need..
在存储库内部,您可以返回延迟加载或完全加载对象对象图的域对象..这取决于您的需要..
Here is a good write up on the same topic...Reconstituting objects
这是一篇关于同一主题的好文章......重构对象
Read the comment by Deyan Petrov on how to use dynamic proxy
阅读 Deyan Petrov 关于如何使用动态代理的评论
回答by Chaos
It's a bit old now but perhaps you should have considered putting the pocos/interfaces in another assembly.
现在有点旧了,但也许您应该考虑将 pocos/接口放在另一个程序集中。
Project.Data references Project.Entities Project.BL references Project.Entities and Project.Data Project.UI references Project.Entities and Project.BL
Project.Data references Project.Entities Project.BL references Project.Entities and Project.Data Project.UI references Project.Entities and Project.BL
Here there are no circular references.
这里没有循环引用。