分离域模型和数据模型 [英] Separating the Domain Model and the Data Model

查看:148
本文介绍了分离域模型和数据模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与此类似:存储库模式和领域模型与实体框架之间的映射.

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

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

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

我了解这两种方法的优点和局限性.我还了解一种方案比另一方案更受青睐的情况.

在线上有很多示例,这些示例显示了如何执行选项1.但是,我找不到任何示例代码,其中显示了如何执行选项2.我在这里阅读了有关选项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实体的构造函数中放置任何验证逻辑吗?

更新18年2月27日

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

解决方案

我发现的每个示例都告诉我不要将验证放入构造函数中.

我认为您需要查找更多示例.

从更深层次上考虑正在发生的事情可能会有所帮助.从根本上说,我们正在尝试做的是确保 DRY原理建议我们更希望在阻塞点捕获前提条件,并确保所有需要该先决条件的代码路径都必须经过该阻塞点.

在Java(DDD开始的地方)和C#中,我们可以使类型系统完成很多繁重的工作;类型系统强制执行对类型的任何使用都要经过构造函数的保证,因此,如果我们在构造函数中确定前提条件成立,那么我们就走了.

这里的关键思想不是构造函数",而是扼要点";使用命名构造器或工厂,可以用作好吧.

如果您的映射代码路径通过了瓶颈,那就太好了.

如果没有...,您将失去类型检查所提供的优势.

一个可能的答案是使您的域模型更加明确;并确认存在未验证的领域概念表示,可以稍后对其进行明确验证.

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

使功能域建模很好地涵盖了这个想法;您可以通过观看Scott Wlaschin的演讲采用F#类型系统的域驱动设计来获得主要主题的预览

My question is similar to this one: Repository pattern and mapping between domain models and Entity Framework.

I have done a lot of reading on here about the following:

1) Mapping the ORM directly to the domain model

2) Mapping the ORM to a data model and then mapping the data model to a domain model (and vice versa)

I understand the benefits and limitations of both approaches. I also understand the scenarios where one approach is favoured over the other.

There are plenty of examples online, which show how to do option 1. However, I cannot find any example code, which shows how to do option 2. I read questions on here about option two like the one referenced on the first line of this post i.e. the question is about option two but the answer is about option one - and there are comments that state that option two may be more appropriate.

Therefore my question is specifically about how to do option one from a mapping and validation perspective:

Mapping

I believe I can do this when mapping the Domain Model to the Data Model:

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

I believe I have do this when mapping the Data Model to the Domain Model in the repository (to protect the invariants):

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

Validation

I want to do this in the PersonDomain class:

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;
   }

}

However, every example I find tells me not to put validation in the constructor. One idea I had was to avoid primitive obsession as follows:

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;
   }

}

However, in this case; there is still validation in the constructor.

Questions

My two questions are:

1) Have I understood the mapping between the Domain Model and Data Model (and vice versa) correctly or is there a more elegant way of approaching this (the mapping between the data model and domain model and vice versa)?

2) Should I be putting any validation logic in the constructor of the PersonDomain Entity in this case?

Update 27/02/18

This link helped me most: http://www.dataworks.ie/Blog/Item/entity_framework_5_with_automapper_and_repository_pattern

解决方案

every example I find tells me not to put validation in the constructor.

I think you need to find more examples.

It may help to think about what's going on at a deeper level. Fundamentally, what we are trying to do is ensure that a precondition holds. One way to do this is to verify the precondition "everywhere"; but the DRY principle suggests that we would prefer to capture the precondition at a choke point, and ensure that all code paths that require that precondition must pass through that choke point.

In Java (where DDD began) and C#, we can get the type system to do a lot of the heavy lifting; the type system enforces the guarantee that any use of the type has gone through the constructor, so if we establish in the constructor that the precondition holds, we're good to go.

The key idea here isn't "constructor", but "choke point"; using a named constructor, or a factory, can serve just as well.

If your mapping code path passes through the choke point, great.

If it doesn't..., you lose the advantage that the type checking was providing.

One possible answer is to make your domain model more explicit; and acknowledge the existence of unvalidated representations of domain concepts, which can later be explicitly validated.

If you squint, you might recognize this as a way of handling inputs from untrusted sources. We explicitly model untrusted data, and let our mapping code produce it for us, and then within the domain model we arrange for the untrusted data to pass through the choke points, and then do work on the sanitized variants.

Domain Modeling Made Functional covers this idea well; you can get a preview of the main themes by watching Scott Wlaschin's talk Domain Driven Design with the F# type System

这篇关于分离域模型和数据模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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