【发布时间】:2017-02-11 09:51:40
【问题描述】:
我目前正在为我们的下一个项目制定架构和模式。我正在考虑使用 DDD,但由于该项目将是中等规模的,因此我试图从代码复制和整体维护的角度使其尽可能简单。
各层如下所示,基本上每一层都是一个单独的组件:
DB -> Domain -> Application -> Web API -> Clients
对于数据库访问,我使用的是 EF Core 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 一起使用,但 Task 和 TaskData 并不相同。在任务实体中,我不需要导航属性 CreatedBy,我只需要一个 Id 就可以了,所以我不想用它不关心的东西污染域。
在数据模型中,我将导航属性用于某些报告,因此这种连接在某些情况下很有用。
如你所见,如果我不能直接映射域实体,我必须在数据层做一些映射。更具体地说,在存储库中通过。手动映射器类。因为我的域实体没有公共 getter 和 setter,所以我无法基于属性将 TaskData 映射到 Task 实体。
这让我想到了纪念品模式,所以我创建了一个新类,这似乎只是普通的 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 };
}
}
如您所见,它需要三个具有不同目的但内容非常相似的类来创建和维护。它只是数据和域层。 “重复”也在其他层继续。
现在,当我决定添加一个新字段时,我需要记住添加它的所有位置并正确分配。恐怕这经常会导致错误,因为团队中的某个人只是忘记更新所有代码。
我能做什么:
在域实体上公开 getter 和 setter,这样我就不需要快照了。 -> 绝对没有!
向 Task 实体添加不必要的属性(CreatedBy 导航)并直接与 ORM 一起使用。 -> 我宁愿不要。
将快照类转换为数据模型并将它们与 ORM 一起使用。 -> 我可能不介意那里的导航属性,但这意味着数据模型是域程序集的一部分。 -> 我不知道,我不喜欢它。
有没有建议我如何在不影响域的情况下有效地减少类的数量或将所有分配(映射)集中到一个地方/映射器类?
谢谢。
【问题讨论】:
-
只是一个问题 - 为什么不先使用代码?这样您就可以直接将数据库映射到您的领域层。
-
我首先使用代码,但是在我的数据模型中我需要定义导航属性,而我在域实体中不需要。所以这两个模型并不完全相同。
-
这里有几个策略:vaughnvernon.co/?p=879
-
“在数据模型中,我对某些报表使用了导航属性,因此这种连接在某些情况下很有用”——我认为将报表移动到不同的限界上下文中可能会使事情变得更容易。这意味着您的 Task 实体将与 TaskData 相同。接下来,如果您将 Task 实体属性 getter 设为 public 并将 setter 设为私有,您也可以将 Task 实体用作您的 EF Persistence 实体。看看@thedatafarm.com/data-access/…
-
@TomShane 为什么你不想威胁 ORM 对象作为域对象?它会让你的生活更轻松。此外,为了让您的 ORM/Domain 模型“丰富”,您可以在业务层中使用扩展方法。
标签: c# entity-framework domain-driven-design