2016-10-03 256 views
0

我目前正在研究我们下一个项目的体系结构和模式。我正在考虑使用DDD,但由于该项目规模中等,我试图从代码重复和整体维护的角度尽可能简化它。DDD,实体框架和实体映射

各层如下所示,基本上每个层是一个单独的组件:

DB -> Domain -> Application -> Web API -> Clients 

对于DB访问我使用EF核心1.0。

这是我目前设计(简化)的数据和域图层中的类,我对此并不满意。

域:

class Task 
{ 
    private int State { get; set; } 
    private string Description { get; set; } 
    private int CreatedById { get; set; }    
} 

数据(EF):

class TaskData 
{ 
    public int State { get; set; } 
    public string Description { get; set; } 
    public int CreatedById { get; set; } 
    public User CreatedBy { get; set; } 
} 

理想情况下,我想直接与ORM使用我的域实体,但任务和TaskData是不相同的。在任务实体中,我不需要导航属性CreatedBy,我很好,只是一个Id,所以我不想污染与它不关心的东西的域。

在数据模型中,我对某些报告使用了导航属性,因此在某些情况下此连接很有用。如你所见,如果我不能直接映射域实体,我必须在数据层做一些映射。更具体地说,在存储库通过。手动映射器类。由于我的域实体没有公共getter和setter,因此我无法将TaskData映射到属性基础上的Task实体。

这使我Memento模式,所以我创造新的类,它似乎只是简单的DTO:

class TaskSnapshot 
{ 
    public int State { get; set; } 
    public string Description { get; set; } 
    public int CreatedById { get; set; } 
} 

而且我原来的工作单位看起来像现在这样:

class Task 
{ 
    ...   
    public Task(TaskSnapshot snapshot) 
    { 
    this.State = snapshot.State; 
    this.Description = snapshot.Description; 
    this.CreateById = snapshot.CreatedById; 
    } 

    public TaskSnapshot ToSnapshot() 
    { 
    return new TaskSnapshot() 
    { 
     State = this.State, 
     Description = this.Description, 
     CreatedBy = this.CreatedBy }; 
    } 
} 

正如你可以看到,它需要三个不同目的的课程,但是要创建和维护的内容非常相似。它只是数据和领域层。 “重复”也在其他层次上继续。

现在,当我决定添加一个新字段时,我需要记住添加它的所有位置以及正确赋值。我担心这往往会导致错误,因为团队中的某个人只是忘记更新所有代码。

我可以做什么:

  1. 制作getter和setter域上的实体公开,这样我就不需要快照。 - >绝对没有!

  2. 将不必要的属性(CreatedBy导航)添加到Task实体,并直接在ORM中使用它。 - >我宁可不要。

  3. 将快照类转换为数据模型并将它们与ORM结合使用。 - >我可能不介意那里的导航属性,但这意味着数据模型是域程序集的一部分。 - >我不知道,我不喜欢它。

有一个建议,我怎么能有效地减少班级人数或集中ALL的分配(映射)到一个地方/映射类不影响域?

谢谢。

+0

只是一个问题 - 为什么不先使用代码?这样您可以直接将数据库映射到您的域图层。 –

+0

我先使用代码,但在我的数据模型中,我需要定义导航属性,这在域实体中并不需要。所以这两个模型是不一样的。 –

+0

这里有几个策略:vaughnvernon.co/?p=879 – jlvaquero

回答

0

根据你的问题下面的评论,我会问的第一个问题是:为什么你不想在域模型中导航属性?正如你所看到的那样,它使映射复杂化,但具体优势是什么?

也看看here,其中说:“通过关联属性导航是DDD中的一个关键概念。”

对我来说,听起来像你可以通过在你的域模型中允许导航属性来保持事情真的很简单 - 比如CreatedBy,为什么它不是你域中的核心概念?当然,你会想禁用延迟加载,并只显式请求加载导航属性。

+0

任务域实体决不会与CreatedBy引用交互。它只是实体中这种类型的许多属性之一。我的主要目标是让域模型尽可能地干净,只有它真正需要的东西。我不想在加载实体根时加载这些引用(仅当生成报告时)。我不喜欢这种不一致的情况,有时它会是空的,有时它会在没有确切理由的情况下被加载。 –

+1

正如我所说,您不必加载它,只在需要时才明确加载。一个参考是null,为什么会污染你的域名?除了“尽可能干净”之外,你还有其他的争论/优点吗?我认为你在这里非常纯粹,但是这往往会导致更多的问题和复杂性,试图解决一些不是真正的问题。无论如何,让我们知道你要采取什么解决方案:) –

+0

我并不是说要对域的清洁感到狂热,我已经准备好做出一些妥协,但我不想从一开始就没有仔细地做评估其他可能性。其他的一点是,我想使用EF Core来进行持久化,但目前它不能很好地支持值对象。问题在于是否使用EF Core,并准备跨层映射(我想避免使用它)或者使用像NHibernate这样的我没有经验的东西。这些决定.. :) –