业务逻辑层和数据访问层:循环依赖

我有一点建筑问题。 在我的项目中,我有一个业务逻辑层(BLL),其中包含我的所有业务规则,模型和接口的OO API。 每个对象都有像getById这样的静态方法,它们返回所述对象的实例。 每个对象也有像save和delete这样的方法。 这是非常简单的OO代码。

现在我有一个DataAccess层(DAL),包含在一个单独的命名空间中,对于每个BLL对象,我有一个DataClass或“Repository”,它执行getById和save命令。 所以在某种程度上,BLL save和getById方法是围绕DataClass方法的薄层。

public static NewsItem GetByID(int id) { return DataFactory.GetNewsItemRepository().GetNewsItemById(id); } 

为了让DataClasses返回BLL对象,他们需要知道BLL。 所以现在我们有:

GUI —> BLL DAL

DataFactory只返回实现接口的对象,因此我可以隐藏“OracleNewsItemRepository”之类的实现细节。

但是现在,自从我开始面向对象编程以来一直困扰着我的事情。 在我目前的解决方案中,BLL和DAL都需要相互了解。 这是循环依赖关系,最佳做法是避免循环依赖关系。 另外我只想暴露接口(和我的DataFactory)而不是我的类。 这可以通过将DAL层放在单独的Assembly中来完成。 这是有道理的。 但是,Visual Studio不允许两个程序集相互引用。 另一个问题是: C#内部访问修饰符

不知怎的,我认为我的整个数据访问模式错了。 感觉就像我正在使用DataMappers等其他东西来卷积ActiveRecord模式。 我花了很多时间在Martin Fowler的网站上,但这些模式被描述得非常通用,并用非常抽象的UML图表来说明。

他们没有解决我的问题。 也许我有点肛门,而且没有“完美的数据访问模式”这样的东西。 而我现在所做的并不是非常错误。 但我现在怎么做,好像……

有任何想法吗?

我认为您的数据访问模式很好。 你没有做的是将你的BLL耦合到OracleDAL。 您正在耦合到DAL接口。 绝对需要一定程度的耦合,否则你永远无法做任何事情。

我假设您的DataFactory和INewsItemRepository类存在于DAL层之外。 以下是我的解决方案组织方式的示例。 我不使用ActiveRecord,所以这可能不适合你。

核心(项目)
  域
    商业实体
  数据
    存储库接口
     **您的DataFactory **

 OracleData(项目)
  数据
     Oracle Repository实现

 SqlData(项目)
  数据
     Sql存储库实现

 UI(项目)

希望这可以帮助。

在我看来:

数据访问层(DAL)应使用以下操作对POCO(普通旧CLR对象)进行操作: SaveNewsItem ( NewsItemDAO newsItemDAO ) 。 POCO是您的DAO(数据访问对象)。

业务层应包含将数据访问对象(DAO)转换为富业务对象的逻辑,这可能只是DAO加上一些操作以及任何装饰/丰富。

DAL应该完全不了解业务逻辑层。 从理论上讲,它应该可以从任何客户端调用。 例如,如果您想从应用程序中分离DAL并将其部署为通过WCF公开自己的单独服务,该怎么办?

如上所述,DAL操作,例如SaveNewsItem应该由BO通过接口访问,可能通过dependency injection/ IoC。

您可以使用接口/dependency injection来解决您的问题。

您的业​​务层(BL)包含(可能不止一个)DAL需要实现的数据访问(DA)接口。 DAL项目具有对BL的项目引用,以便它们可以吐出业务对象(BO)并实现DA接口。

您的BO可以调用DataFactory,它可以通过dependency injection或reflection来实例化DA对象。

我在工作中的许多应用程序(基于Web和智能客户端)中都使用了这种模式,并且它的工作非常精彩。

它现在有点旧了,但也许您应该考虑将pocos /接口放在另一个程序集中。

 Project.Data references Project.Entities Project.BL references Project.Entities and Project.Data Project.UI references Project.Entities and Project.BL 

这里没有循环引用。

需要明确的是,我喜欢将业务模型和业务逻辑视为两个独立的层。 您的业​​务模型是您的POCO(普通旧CLR对象)。 您的业​​务逻辑层将负责使用您的业务模型和DAL接口执行validation,事务等,这些接口可以通过多种方式连接(Spring,Castle或您自己的本地IoC容器)。

使用业务模型在DAL中实现零依赖关系的好方法是使用已构建的对象关系映射框架(ORM),例如NHibernate(我最喜欢的ORM框架的无耻插件)。

IceHeat,@ Claig Wilson的例子最有意义,它可能源于这篇文章: http : //www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx 。

这是值得一读的,并解决域驱动的开发,它解决了您在这里遇到的问题。 我建议任何人,即使你不给猴子NHibernate这是一篇伟大的文章。

我会从你的BLL(域模型)中删除任何Get()和Save()方法..这就是我要做的

GUI将要求Repository通过id获取域对象..一旦GUI具有域对象,您可以将其导航到其他对象。这样,Domain层不需要知道有关存储库的任何信息。

在内部存储库中,您可以返回懒惰加载或完全加载对象对象图的域对象..这将取决于您的需要..

这是一篇关于同一主题的好文章… 重构对象

阅读Deyan Petrov关于如何使用动态代理的评论

DAL必须是抽象的,因此它必须只包含与后端数据库交互的普通ADO.NET对象,例如连接DataAdapter,DataReader等。 有了这些,您可以在您的Biz层中引用DAL,当涉及到具有一点抽象的实体时,您可以解决所有问题,例如,如果您有客户类,您可以创建一个abstaractoin客户类来实现与DAL交互的基本操作(如保存,更新和检索数据)和另一个inheritance抽象类的类重写基类方法实现以满足您的Bizvalidation等。