Orm 业务对象/数据库访问层的体系结构

Orm 业务对象/数据库访问层的体系结构,orm,architecture,Orm,Architecture,出于各种原因,我们正在编写一个新的业务对象/数据存储库。该层的需求之一是将业务规则的逻辑与实际的数据存储层分离 可以有多个数据存储层来实现对同一对象的访问,例如,实现大多数对象的主“数据库”数据存储源和实现用户对象的另一个“ldap”源。在这个场景中,用户可以选择来自LDAP源,可能具有稍微不同的功能(例如,不可能保存/更新用户对象),但是应用程序使用它的方式是相同的。另一种数据存储类型可能是web服务或外部数据库 我们正在考虑两种主要的方法来实现这一点,我和一位同事在一个基本的层面上存在分歧,

出于各种原因,我们正在编写一个新的业务对象/数据存储库。该层的需求之一是将业务规则的逻辑与实际的数据存储层分离

可以有多个数据存储层来实现对同一对象的访问,例如,实现大多数对象的主“数据库”数据存储源和实现用户对象的另一个“ldap”源。在这个场景中,用户可以选择来自LDAP源,可能具有稍微不同的功能(例如,不可能保存/更新用户对象),但是应用程序使用它的方式是相同的。另一种数据存储类型可能是web服务或外部数据库

我们正在考虑两种主要的方法来实现这一点,我和一位同事在一个基本的层面上存在分歧,这是正确的。我想听听关于哪一个最好用的建议。我会尽量保持我对每一个的描述尽可能中立,因为我在这里寻找一些客观的观点

  • 业务对象是基类,数据存储对象继承业务对象。客户机代码处理数据存储对象

    在这种情况下,公共业务规则由每个数据存储对象继承,客户机代码直接使用的是数据存储对象

    这意味着客户机代码决定对给定对象使用哪种数据存储方法,因为它必须显式声明该类型对象的实例。客户机代码需要明确知道它所使用的每种数据存储类型的连接信息

    如果数据存储层为给定对象实现了不同的功能,那么客户机代码在编译时会明确地知道它,因为对象看起来不同。如果更改了数据存储方法,则必须更新客户端代码

  • 业务对象封装数据存储对象

    在这种情况下,客户机应用程序直接使用业务对象。客户端应用程序将基本连接信息传递给业务层。由业务对象代码决定给定对象使用哪种数据存储方法。连接信息是从配置文件中获取的一块数据(客户端应用程序并不真正了解/关心它的详细信息),可能是数据库的单个连接字符串,也可能是各种数据存储类型的多个连接字符串。还可以从另一个点读取其他数据存储连接类型,例如,数据库中的配置表,该表指定指向各种web服务的URL

    这里的好处是,如果将新的数据存储方法添加到现有对象中,则可以在运行时设置配置设置以确定要使用哪种方法,并且对客户端应用程序完全透明。如果给定对象的数据存储方法发生更改,则不需要修改客户端应用程序

  • 业务对象是基类,数据源对象继承自业务对象。客户机代码主要处理基类

    这与第一个方法类似,但客户机代码声明基本业务对象类型的变量,业务对象上的Load()/Create()/etc静态方法返回适当的数据源类型的对象

    此解决方案的体系结构类似于第一种方法,但主要区别在于,对于给定的业务对象,由业务层而不是客户机代码决定使用哪个数据存储对象

我知道已经有一些现有的ORM库提供了这些功能,但是现在请不要考虑这些功能(有可能数据存储层是用其中一个ORM库实现的)-还要注意,我故意不告诉您这里使用的是什么语言,只是它是强类型的


我在这里寻找一些关于哪种方法更适合使用的一般性建议(或者可以自由地提出其他建议),以及为什么

我是否可以建议另一种可能更好地解耦的替代方案:业务对象使用数据对象,数据对象实现存储对象。这应将业务规则保留在业务对象中,但不依赖于存储源或格式,同时允许数据对象支持所需的任何操作,包括动态更改存储对象(例如,用于在线/离线操作)


这属于上面的第二类(业务对象封装数据存储对象),但更清楚地将数据语义与存储机制分开

客户机不应直接处理存储对象。它们可以直接处理DTO,但任何具有存储逻辑的对象(未包装在业务对象中)都不应由客户机直接调用。

您还可以保留一个门面,不让客户直接调用业务。它还为您的业务创建了通用的入口点

如前所述,除了DTO和Facade之外,您的业务不应该暴露于任何东西


对。您的客户可以处理DTO。这是通过应用程序传递数据的理想方式。

请查看Rocky Lhotka提供的CSLA.net

里昂证券成立已久。 然而,我喜欢埃里克·埃文斯书中讨论的方法

好吧,我来了,同事格雷格提到

格雷格非常准确地描述了我们一直在考虑的备选方案。我只想在情况描述中添加一些额外的注意事项

客户机代码可能不知道存储业务对象的数据存储,但可能只有一个数据存储,或者同一业务对象类型(存储在本地数据库和外部LDAP中的用户)有多个数据存储,但客户机不创建这些业务对象
using(MyConcreteBusinessContext ctx = new MyConcreteBusinessContext("datares://model1?DataSource=myserver;Catalog=mydatabase;Trusted_Connection=True ruleres://someruleresource?type=StaticRules&handler=My.Org.Business.Model.RuleManager")) {

User user = ctx.GetUserById("SZE543");
user.IsLogonActive = false;
ctx.Save();
}

//a business object
class User : BusinessBase {
  public User(BusinessContext ctx) : base(ctx) {}

  public bool Validate() {
    IValidator v = ctx.GetValidator(this);
    return v.Validate();
  }
}

// a validator
class UserValidator : BaseValidator, IValidator {
 User userInstance;
 public UserValidator(User user) {
  userInstance = user;
 }

 public bool Validate() {
   // actual validation code here
   return true;
 }
}