DDD中的数据访问层设计 [英] Data access layer design in DDD

查看:401
本文介绍了DDD中的数据访问层设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对不起,我的英语不好.

好吧,我现在正在考虑DDD方法,这听起来不错,但是...有一个小问题. DDD表示,域模型层与数据访问层(以及所有其他层)完全脱钩.因此,当DAL保存一些业务对象时,它只能访问该对象的公共属性.现在的问题:

我们一般如何保证对象的一组公共数据 是我们以后需要还原的对象吗?

示例

我们有以下业务规则:

  1. 在创建时必须为业务对象提供用户和域.
  2. 创建对象后无法更改用户和域.
  3. 业务对象具有类似于"user @ domain"的电子邮件"属性.

这里是描述这些规则的纯POCO:

 public class BusinessObject
{
    private string _user;
    private string _domain;

    public BusinessObject(string user, string domain)
    {
        _user = user;
        _domain = domain;
    }

    public string Email
    {
        get { return _user + "@" + _domain; }
    }
}
 

因此,DAL有时会将此对象保存到外部存储(即SQL数据库).显然,DAL会将电子邮件"属性保存到DB中的关联字段.一切正常,直到我们要求DAL还原对象的那一刻. DAL如何做到这一点?该对象至少必须具有电子邮件"字段的公共设置器.像

 public string Email
{
    set
    {
        string[] s = value.Split("@");
        _user = s[0];
        _domain = s[1];
    }
}
 

实际上,该对象将同时具有用户"和域"字段以及方法GetEmail()的公共获取器/设置器.别说了我不希望我的POCO具有这种功能!没有任何业务规则.必须这样做才能仅保存/恢复对象.

我看到了另一个选择.可以要求作为DAL一部分的ORM存储恢复该对象所需的所有专用字段.但是,如果我们想将域模型与DAL分开,则这是不可能的. DAL不能依赖业务对象的某些私有成员.

我看到的唯一解决方法是拥有一些系统级仪器,该仪器可以为我们创建对象的转储并可以随时从此转储中恢复对象.并且DAL除了对象的公共属性外,还必须将此转储放入存储中.因此,当DAL需要从存储中还原对象时,它将为此使用转储.当DAL执行不需要实例化对象的操作(即大多数link2sql查询)时,可以使用保存到存储中的公共属性.

我做错了吗?我需要阅读更多内容吗?关于某些模式,也许是ORM?

解决方案

我认为您认为这部分内容有误:

我看到了另一个选择.作为DAL一部分的ORM可能是 要求存储还原对象所需的所有私有字段. 但这是不可能的,如果我们想将域模型分开 来自DAL. DAL不能依赖于DAL的某些私人成员 业务对象.

域模型不依赖于DAL.相反,DAL取决于域模型. ORM对域对象(包括私有字段)有深入的了解.这绝对没有错.实际上,这是在DDD中实施永久性无知的最佳方法.这是Domain类的外观.请注意

  • 字段可以是私有字段,也可以是只读字段
  • public构造函数仅由客户端代码使用,而不由DAL使用.
  • 不需要属性获取器和设置器
  • 业务对象几乎100%不了解持久性问题

DAL/ORM唯一需要的是私有无参数构造函数:

public class BusinessObject {
    private readonly string _user;
    private readonly string _domain;

    private BusinessObject(){}

    public BusinessObject(string user, string domain) {
        _user = user;
        _domain = domain;
    }

    public string Email {
        get { return _user + "@" + _domain; }
    }
}

魔术发生在ORM中. Hibernate可以使用以下映射文件从数据库还原该对象:

<class name="BusinessObject" table="BusinessObjects">
    ...
    <property name="_user" column="User" />
    <property name="_domain" column="Domain" />
    ...
</class>

不了解持久性的域代码的另一方面是 DDD存储库:

定义:存储库是一种封装存储的机制, 模仿对象集合的检索和搜索行为.

存储库接口属于Domain,并且应尽可能基于无所不在的语言.另一方面,存储库实现属于DAL(依赖反转原理).

Excuse me for my poor English.

Ok, I'm thinking about DDD approach now and it sounds great but... There is one little question about it. DDD says that the domain model layer is totally decoupled from the data access layer (and all other layers). So when the DAL will save some business object it will have access to public properties of this object only. Now the question:

How can we guarantee (in general) that a set of public data of an object is all we need to restore the object later?

Example

We have the following business rules:

  1. User and domain must be provided for the business object on create.
  2. User and domain cannot be changed after object creation.
  3. The business object have the Email property which looks like "user@domain".

Here is a pure POCO which describes those rules:

public class BusinessObject
{
    private string _user;
    private string _domain;

    public BusinessObject(string user, string domain)
    {
        _user = user;
        _domain = domain;
    }

    public string Email
    {
        get { return _user + "@" + _domain; }
    }
}

So at some moment the DAL will save this object to the external storage (i.e. SQL database). Obviously, the DAL will save the "Email" property to the associated field in DB. Everything will work just fine until the moment when we'll ask the DAL to restore the object. How the DAL can do this? The object must have a public setter for the "Email" field at least. Something like

public string Email
{
    set
    {
        string[] s = value.Split("@");
        _user = s[0];
        _domain = s[1];
    }
}

Actually, the object will have public getters/setters for both "User" and "Domain" fields and method GetEmail(). But stop. I don't want my POCO to have such functionality! There are no business rules for it. This must be done for the ability to save/restore the object only.

I see another option. The ORM which is a part of the DAL could be asked to store all of the private fields needed to restore the object. But this is impossible if we want to keep the domain model separated from the DAL. The DAL cannot rely on certain private members of the business object.

The only workaround I can see is to have some system-level instrument which can create the dump of the object for us and can restore object from this dump anytime. And the DAL must put this dump to the storage in addition to public properties of the object. So when the DAL needs to restore the object from storage it will use the dump for this. And the public properties saved to storage can be used when the DAL is performing operations that don't need the object to be instantiated (i.e. most of link2sql queries).

Am I doing it wrong? Do I need read more? About some patterns, ORM's maybe?

解决方案

I think you got this part wrong:

I see another option. The ORM which is a part of the DAL could be asked to store all of the private fields needed to restore the object. But this is impossible if we want to keep the domain model separated from the DAL. The DAL cannot rely on certain private members of the business object.

Domain model does not depend on DAL. Its the other way around, DAL depends on Domain model. ORM has intimate knowledge of Domain Objects, including private fields. There is absolutely nothing wrong with that. In fact this is the best way to implement persistent-ignorance in DDD. This is how the Domain class can look like. Note that

  • fields can be private and readonly
  • public Constructor is only used by client code, not by DAL.
  • no need for property getters and setters
  • Business object is almost 100% ignorant of persistence issues

The only thing DAL/ORM needs is private parameterless consturctor:

public class BusinessObject {
    private readonly string _user;
    private readonly string _domain;

    private BusinessObject(){}

    public BusinessObject(string user, string domain) {
        _user = user;
        _domain = domain;
    }

    public string Email {
        get { return _user + "@" + _domain; }
    }
}

And the magic happens in ORM. Hibernate can restore this object from database using this mapping file:

<class name="BusinessObject" table="BusinessObjects">
    ...
    <property name="_user" column="User" />
    <property name="_domain" column="Domain" />
    ...
</class>

Another aspect of persistence-ignorant domain code is DDD Repository:

Definition: A Repository is a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects.

Repository interface belongs to Domain and should be based on Ubiquitous Language as much as possible. Repository implementation on the other hand belongs to DAL (Dependency Inversion Principle).

这篇关于DDD中的数据访问层设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆