我应该如何使用持久层的私有 setter 实现 DDD 实体?
How should I materialize DDD entities with private setters from the persistence layer?
我才刚刚开始了解 DDD。贫血领域模型(据我所知,实际上只不过是持久性模型)并将逻辑推入视图模型并没有削减它。因此,我对其中一个更复杂的上下文(提要 nutrition/price 优化器)进行了建模。我完全赞同这样一个事实,即 DDD 实体具有私有设置器并公开只读集合,并且改变它们的唯一方法是调用实体上的方法。非常容易测试,很难被滥用。
这是我的问题。直接把这个东西存到数据库里就行了。对我来说不明显的是如何在不破坏封装的情况下再次实现它。
我一直在使用 Entity Framework 加载数据模型。我知道它能够使用域实体的私有设置器,但是:1) 反射的魔力可能会误导推理。 2) 我绝对不想尝试跳过数据模型并强制领域模型尝试与 EF 一起玩。 3)数据库的规范化程度略低于领域模型。 4) 我认为 EF 与 IReadOnlyList<>
.
配合得不好
我还尝试重建和重放方法调用,这会使实体处于等效状态,但这似乎是不必要的复杂性。代码是否正确对我来说并不明显。而且这种方法会触发相当多的线性规划求解和滞后。
为了保持域实体的清洁,我能想到的最后一招是在每个名为 Materialize
的实体上使用一个内部静态工厂方法,它接收字段作为参数和 returns 一个新的实体的实例。存储库应该是唯一访问它的东西。这是一个好的解决方案吗?我还应该考虑什么?
编辑:我没有具体化保存的状态,而是让我的存储库模拟事件源(重放方法)。我喜欢这个方向。数据库还不是事件源,但可以随时轻松切换,因为存储库隐藏了它。
基本上你想使用 Memento 模式,它很结实但很无聊,而且维护成本很高。很高兴您意识到直接使用 EF 实体(无论它们如何 POCO)是一个问题,但是有一个简单的解决方案。
将您的 EF POCO 严格视为来自数据库的 read/write 的 DTO。如果您正确使用 Repository pattern,那么您可以将聚合根映射(手动或使用自动映射器)到 EF POCO inside 存储库。
应用程序的其余部分不会知道任何有关 EF 的信息,只有您的存储库将作为 'converter' 从域对象到一个或多个 EF POCO 并返回。为了将数据放入域对象中,您可以定义 'read-only' 属性,例如
List<string> _data=new List<string>();
public IEnumerable<string> Data
{
get{ return _data;}
private set{
_data=value.ToList();
}
}
这将允许像自动映射器这样的工具填充对象状态。请注意,对象仍然是封装的,但私有 setter 也充当数据 'importers'.
就我个人而言,我正在使用这种方法但没有使用 EF,因为我更喜欢 json 对象并按原样存储它。 Ofc,table 具有查询所需的列,但 Data
列保存可以轻松恢复的对象状态。只要您的聚合设计得当,它就可以很好地工作。
我才刚刚开始了解 DDD。贫血领域模型(据我所知,实际上只不过是持久性模型)并将逻辑推入视图模型并没有削减它。因此,我对其中一个更复杂的上下文(提要 nutrition/price 优化器)进行了建模。我完全赞同这样一个事实,即 DDD 实体具有私有设置器并公开只读集合,并且改变它们的唯一方法是调用实体上的方法。非常容易测试,很难被滥用。
这是我的问题。直接把这个东西存到数据库里就行了。对我来说不明显的是如何在不破坏封装的情况下再次实现它。
我一直在使用 Entity Framework 加载数据模型。我知道它能够使用域实体的私有设置器,但是:1) 反射的魔力可能会误导推理。 2) 我绝对不想尝试跳过数据模型并强制领域模型尝试与 EF 一起玩。 3)数据库的规范化程度略低于领域模型。 4) 我认为 EF 与 IReadOnlyList<>
.
我还尝试重建和重放方法调用,这会使实体处于等效状态,但这似乎是不必要的复杂性。代码是否正确对我来说并不明显。而且这种方法会触发相当多的线性规划求解和滞后。
为了保持域实体的清洁,我能想到的最后一招是在每个名为 Materialize
的实体上使用一个内部静态工厂方法,它接收字段作为参数和 returns 一个新的实体的实例。存储库应该是唯一访问它的东西。这是一个好的解决方案吗?我还应该考虑什么?
编辑:我没有具体化保存的状态,而是让我的存储库模拟事件源(重放方法)。我喜欢这个方向。数据库还不是事件源,但可以随时轻松切换,因为存储库隐藏了它。
基本上你想使用 Memento 模式,它很结实但很无聊,而且维护成本很高。很高兴您意识到直接使用 EF 实体(无论它们如何 POCO)是一个问题,但是有一个简单的解决方案。
将您的 EF POCO 严格视为来自数据库的 read/write 的 DTO。如果您正确使用 Repository pattern,那么您可以将聚合根映射(手动或使用自动映射器)到 EF POCO inside 存储库。
应用程序的其余部分不会知道任何有关 EF 的信息,只有您的存储库将作为 'converter' 从域对象到一个或多个 EF POCO 并返回。为了将数据放入域对象中,您可以定义 'read-only' 属性,例如
List<string> _data=new List<string>();
public IEnumerable<string> Data
{
get{ return _data;}
private set{
_data=value.ToList();
}
}
这将允许像自动映射器这样的工具填充对象状态。请注意,对象仍然是封装的,但私有 setter 也充当数据 'importers'.
就我个人而言,我正在使用这种方法但没有使用 EF,因为我更喜欢 json 对象并按原样存储它。 Ofc,table 具有查询所需的列,但 Data
列保存可以轻松恢复的对象状态。只要您的聚合设计得当,它就可以很好地工作。