DDD中的数据访问层设计

时间:2011-09-09 17:32:31

标签: orm domain-driven-design poco data-access-layer

请原谅我的英语不好。

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

  

我们如何保证(通常)一组对象的公共数据   我们需要在以后恢复该对象吗?

示例

我们有以下业务规则:

  1. 必须在创建时为业务对象提供用户和域。
  2. 创建对象后无法更改用户和域。
  3. 业务对象的Email属性类似于“user @ domain”。
  4. 这是一个描述这些规则的纯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会将“Email”属性保存到DB中的关联字段。一切都会正常工作,直到我们要求DAL恢复对象。 DAL如何做到这一点?对象必须至少具有“电子邮件”字段的公共设置器。像

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

    实际上,该对象将为“User”和“Domain”字段以及方法GetEmail()提供公共getter / setter。但是停下来。我不希望我的POCO拥有这样的功能!它没有业务规则。必须这样才能保存/恢复对象。

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

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

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

2 个答案:

答案 0 :(得分:5)

我认为你错了这个部分:

  

我看到另一种选择。作为DAL一部分的ORM可以是   要求存储恢复对象所需的所有私有字段。   但如果我们想要保持域模型分离,这是不可能的   来自DAL。 DAL不能依赖某些私人成员   业务对象。

域模型不依赖于DAL。相反,DAL依赖于Domain模型。 ORM熟悉Domain Objects,包括私有领域。这绝对没有错。实际上,这是在DDD中实现持久无知的最佳方式。这就是Domain类的外观。注意

  • 字段可以是私有的和只读的
  • public Constructor仅由客户端代码使用,而不是由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 Repository

  

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

存储库接口属于Domain,应尽可能基于Ubiquitous Language。另一方面,存储库实现属于DAL(Dependency Inversion Principle)。

答案 1 :(得分:1)

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

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

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

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

一个简单的解决方案就是让你的DAL调用新的BusinessObject(电子邮件)