分离域模型和数据模型

时间:2018-02-20 11:38:53

标签: c# nhibernate domain-driven-design

我的问题与此类似:Repository pattern and mapping between domain models and Entity Framework

我在这里做了很多关于以下内容的阅读:

1)将ORM直接映射到域模型

2)将ORM映射到数据模型,然后将数据模型映射到域模型(反之亦然)

我理解这两种方法的好处和局限。我也理解一种方法比另一方更受青睐的情景。

网上有很多例子,展示了如何做选项1.但是,我找不到任何示例代码,它显示了如何做选项2.我在这里阅读关于选项二的问题,如第一个引用的那个这篇文章的一行,即问题是关于选项二,但答案是关于选项一 - 而且有评论指出选项二可能更合适。

因此,我的问题是关于如何从映射和验证角度做选项一:

映射

我相信在将域模型映射到数据模型时我可以这样做:

public PersonDomain GetById(Guid id)
{
    return AutoMapper.Mapper.Map<PersonDomain>(Session.Get<PersonData>(id)); 
}

我相信在将数据模型映射到存储库中的域模型时(保护不变量),我已经这样做了:

protected PersonDomain ToPersonDomain(PersonData personData) 
{
    return new PersonDomain(personData.ID, personData.Name, personData.DateOfBirth);
}

验证

我想在PersonDomain类中执行此操作:

public class PersonDomain
{
   public Guid ID{ get; private set; }
   public DateTime DateOfBirth { get; private set; }
   public string Name { get; private set; }

   public PersonDomain(Guid id, DateTime dateOfBirth, string name)
   {
    if (id == Guid.Empty())
      throw new ArguementException("Guid cannot be empty");
    if (name =="")
       throw new ArguementException("Name cannot be empty");
    ID=id;
    Name=NAME;
    DateOfBirth=dateOfBirth;
   }

}

然而,我发现的每个例子都告诉我不要在构造函数中加入验证。我的一个想法是避免原始的痴迷如下:

public class PersonDomain
{
   public ID ID{ get; private set; }
   public DateOfBirth DateOfBirth { get; private set; }
   public Name Name { get; private set; }

   public PersonDomain(ID id, DateOfBirth dateOfBirth, Name name)
   {
    if (id == null)
      throw new ArguementNullException("ID cannot be null");
    if (name ==null)
       throw new ArguementNullException("Name cannot be null");
    ID=id;
    Name=name;
    DateOfBirth=dateOfBirth;
   }

}

然而,在这种情况下;仍然在构造函数中进行验证。

问题

我的两个问题是:

1)我是否正确理解了域模型和数据模型之间的映射(反之亦然),还是有更优雅的方法来处理这种情况(数据模型和域模型之间的映射,反之亦然)?

2)在这种情况下,我应该在PersonDomain实体的构造函数中放置任何验证逻辑吗?

更新27/02/18

此链接对我最有帮助:http://www.dataworks.ie/Blog/Item/entity_framework_5_with_automapper_and_repository_pattern

2 个答案:

答案 0 :(得分:4)

  

我发现的每个例子都告诉我不要在构造函数中放置验证。

我认为你需要找到更多的例子。

考虑在更深层次上发生的事情可能会有所帮助。从根本上说,我们要做的是确保precondition成立。一种方法是验证“无处不在”的前提条件;但是DRY principle表明我们更愿意在阻塞点捕获前置条件,并确保所有需要该前置条件的代码路径必须通过该阻塞点。

在Java(DDD开始的地方)和C#中,我们可以让类型系统做很多繁重的工作;类型系统强制保证任何类型的使用都经过构造函数,所以如果我们在构造函数中建立前置条件,我们就可以了。

这里的关键思想不是“构造函数”,而是“阻塞点”;使用named constructor或工厂也可以提供服务。

如果您的映射代码路径通过阻塞点,那就很好。

如果没有...,则会失去类型检查所提供的优势。

一个可能的答案是让您的域模型更加明确;并承认存在未经验证的域概念表示,以后可以明确验证。

如果您眯着眼睛,您可能会认识到这是处理来自不受信任来源的输入的一种方式。我们明确地为不受信任的数据建模,让我们的映射代码为我们生成它,然后在域模型中我们安排不受信任的数据通过阻塞点,然后对已经过消毒的变体进行处理

Domain Modeling Made Functional很好地涵盖了这个想法;您可以通过观看Scott Wlaschin的演讲Domain Driven Design with the F# type System

来预览主要主题

答案 1 :(得分:0)

  

1)我是否理解了域模型和数据之间的映射   模型(反之亦然)正确或有更优雅的方式   接近这个(数据模型和域模型之间的映射)   反之亦然)?

我会说ORM应该将域模型(实体)映射到数据库,而您将使用数据模型将数据表示到外部世界(UI) ,REST ......)。

  

2)我应该在构造函数中放置任何验证逻辑吗?   在这种情况下,PersonDomain实体?

将域验证逻辑放入域对象构造函数中是可以的。但是如果你想进行特定于UI的验证,它应该可以在映射到数据模型的一些验证类中完成,这样你就可以向用户返回一个很好的错误。