Domain driven design 存储库添加和创建方法
为什么存储库的Domain driven design 存储库添加和创建方法,domain-driven-design,repository-pattern,data-access-layer,ddd-repositories,Domain Driven Design,Repository Pattern,Data Access Layer,Ddd Repositories,为什么存储库的.Add方法通常实现为接受要添加的实体实例,并且.Id已经“设置”(尽管可以通过反射再次设置),这应该是repo的责任? 将其实现为.CreateAndAdd,不是更好吗 例如,给定一个人实体: public class Person { public Person(uint id, string name) { this.Id = id; this.Name = name; } public uint Id { g
.Add
方法通常实现为接受要添加的实体实例,并且.Id
已经“设置”(尽管可以通过反射再次设置),这应该是repo的责任?将其实现为
.CreateAndAdd
,不是更好吗
例如,给定一个人
实体:
public class Person
{
public Person(uint id, string name)
{
this.Id = id;
this.Name = name;
}
public uint Id { get; }
public string Name { get; }
}
为什么存储库通常实现为:
public interface IRpository<T>
{
Task<T> AddAsync(T entity);
}
公共接口Ipository
{
任务AddAsync(T实体);
}
而不是:
public interface IPersonsRpository
{
Task<Person> CreateAndAddAsync(string name);
}
公共接口IPERSOnspository
{
任务CreateAndAddAsync(字符串名称);
}
为什么存储库通常实现为
有几个原因
从历史上看,领域驱动设计
深受引入该术语的Eric Evans书的影响。在那里,Evans建议存储库提供集合语义,提供“内存中集合的幻觉”
在人的集合中添加字符串
,甚至是姓名
,没有多大意义
更广泛地说,找出如何从一组参数中重构实体是存储的一项独立职责,因此,去那里可能没有意义(注意:存储库通常负责从存储的纪念品中重新构建实体,因此它并不完全是外来的,但通常有一个额外的抽象,即“工厂”,真正起作用。)
使用通用存储库接口通常是有意义的,因为通过检索/存储操作与集合中的单个元素交互不需要大量定制。存储库可以支持对不同类型实体的定制查询,因此专门调用它可能会很有用
public interface IPersonRepository : IRepository<Person> {
// Person specific queries go here
}
公共接口IPersonRepository:IRepository{
//特定于个人的查询转到此处
}
最后,
id
…事实是身份,作为一个概念,有很多“它取决于”在某些情况下,存储库为一个实体分配一个id可能是有意义的——例如,使用数据库生成的唯一键。通常,您会希望在存储库之外控制标识符。马匹用于课程。关于这个问题已经有了很好的答案,我只想添加一些我的想法。(它将包含一些与上一个答案重复的内容,因此如果这是一件坏事,请告诉我,我将删除它:))
ID生成的职责可以属于组织或系统的不同部分
有时,ID将由一些特殊规则生成,例如。此编号可用于系统中人员的ID,因此在创建人员实体之前,必须从特定的SSNGenerator服务生成此代码
我们可以使用随机生成的ID,比如UUID。UUID可以在存储库之外生成,并在创建过程中分配给实体,存储库只会将其存储(添加、保存)到数据库中
由数据库生成的ID非常有趣。您可以使用RDBMS中的顺序ID、MonogoDB中的UUID或一些散列。在这种情况下,ID生成的责任分配给DB,因此它只能在存储实体后发生,而不是在创建实体时发生。(我在这里允许自己自由,因为您可以在保存事务或阅读最后一个事务之前生成它,等等。但我喜欢在这里进行概括,避免讨论带有竞争条件和冲突的情况)。这意味着您的实体在保存完成之前没有标识。这是好事吗?当然要视情况而定:)
这个问题就是一个很好的例子
当您实施一个解决方案时,有时使用的技术会影响它。例如,您必须处理这样一个事实,即ID是由数据库生成的,该数据库是基础设施的一部分(如果您在代码中定义了这样一个层)。即使使用RDBMS,您也可以通过使用s UUID来避免这种情况,但是您必须在这些ID上加入(同样是特定于技术的东西:),所以有时候人们喜欢使用默认值
你可以使用Save方法,而不是Add或AddAndCreate来做同样的事情,这只是一些人喜欢的一个不同的术语。存储库确实经常被定义为“内存中的集合”,但这并不意味着我们必须严格遵守它(大多数时候这样做可能是一件好事,但仍然…)
如前所述,如果数据库生成ID,存储库似乎是分配ID(存储之前或之后)的一个很好的候选者,因为它是与数据库对话的那个
如果您以生成ID的方式使用事件,则会影响事情。例如,假设您想要将UserID作为s属性的UserRegisteredEvent。如果使用DB生成ID,则必须先存储用户,然后创建并存储/调度事件或执行类似操作。另一方面,如果事先生成ID,则可以将事件和实体一起保存(在事务或同一文档中并不重要)。有时这会变得棘手
背景、技术和框架方面的经验、对文学、学校和工作中术语的接触会影响我们对事物的看法,以及什么术语对我们来说更合适。此外,我们(大部分时间)在团队中工作,这会影响我们如何命名事物以及如何实现它们。使用定义:
存储库在域和数据映射层之间进行调解,
作用类似于内存中的域对象集合。客户端对象
以声明方式构造查询规范