CQRS DDD - 命令和域模型关系
CQRS DDD - Commands and Domain Models relationship
我正在练习尽我所能使用 CQRS 和 DDD 来实施一个项目,并且在构建命令后提出了一个问题。
场景:用户发送命令在系统中创建一个书架,该书架本身也可以包含一个图书集合。
命令如下所示:
public class CreateNewBookShelfCommand : ICommand
{
public long CommandInitiatorId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Book> Books { get; set; }
}
所有 Commands
都位于 Contracts
项目中,该项目本身位于 Application
解决方案文件夹中。
驻留在 Domain
解决方案文件夹中的 Model
项目托管 BookShelf
实体 class,其中包括书籍集合。
问题 1: 上面的命令有这个 Books
属性 类型 Book
。我的问题是:Commands
项目是否应该直接引用模型项目,以便 Book
数据类型在 CreateNewBookShelfCommand
中解析?我个人认为 Contracts
不允许引用除 CommandHandlers
以外的任何项目或任何其他可能 Cross Cutting 的项目。
问题 2: 那么,在 Contracts
项目中复制 Book
实体 class 的一部分是否是一个好习惯并在 CreateNewBookShelfCommand
?
这是我为 Book
和 BookShelf
:
准备的模型项目
public class BookShelf : BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public BookShelfAccess Access { get; set; }
public virtual BookShelfOwner Owner { get; set; }
public long OwnerId { get; set; }
public ICollection<Book> Books { get; set; }
}
public class Book : BaseEntity
{
public string Name { get; set; }
public DateTime? PublishedAt { get; set; }
public int NumberOfPublishes { get; set; }
public virtual BookShelf Shelf { get; set; }
public long ShelfId { get; set; }
}
我希望我的解释已经足够了,如果有任何其他信息我应该在这里添加,请告诉我。
通常,您不会将域模型中的实体用作命令的元素。
命令基本上是消息,因此它们确实应该是不可变的。你想知道收到的和发送的是一样的。在 DDD 术语中,您可能会将消息视为 值对象。
将域模型中的实体用作命令的内存表示的一部分没有意义,因为您永远不应该调用任何更改其状态的实体方法。
命令在本质上更接近于数据传输对象,而不是域模型实体。
通常,您系统中的所有实体对象都应该存在于聚合根接口之后,您传递给该接口的参数是 值 。如果领域模型需要一个实体,它可以根据提供的值创建一个实体。
我正在练习尽我所能使用 CQRS 和 DDD 来实施一个项目,并且在构建命令后提出了一个问题。
场景:用户发送命令在系统中创建一个书架,该书架本身也可以包含一个图书集合。
命令如下所示:
public class CreateNewBookShelfCommand : ICommand
{
public long CommandInitiatorId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Book> Books { get; set; }
}
所有 Commands
都位于 Contracts
项目中,该项目本身位于 Application
解决方案文件夹中。
驻留在 Domain
解决方案文件夹中的 Model
项目托管 BookShelf
实体 class,其中包括书籍集合。
问题 1: 上面的命令有这个 Books
属性 类型 Book
。我的问题是:Commands
项目是否应该直接引用模型项目,以便 Book
数据类型在 CreateNewBookShelfCommand
中解析?我个人认为 Contracts
不允许引用除 CommandHandlers
以外的任何项目或任何其他可能 Cross Cutting 的项目。
问题 2: 那么,在 Contracts
项目中复制 Book
实体 class 的一部分是否是一个好习惯并在 CreateNewBookShelfCommand
?
这是我为 Book
和 BookShelf
:
public class BookShelf : BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public BookShelfAccess Access { get; set; }
public virtual BookShelfOwner Owner { get; set; }
public long OwnerId { get; set; }
public ICollection<Book> Books { get; set; }
}
public class Book : BaseEntity
{
public string Name { get; set; }
public DateTime? PublishedAt { get; set; }
public int NumberOfPublishes { get; set; }
public virtual BookShelf Shelf { get; set; }
public long ShelfId { get; set; }
}
我希望我的解释已经足够了,如果有任何其他信息我应该在这里添加,请告诉我。
通常,您不会将域模型中的实体用作命令的元素。
命令基本上是消息,因此它们确实应该是不可变的。你想知道收到的和发送的是一样的。在 DDD 术语中,您可能会将消息视为 值对象。
将域模型中的实体用作命令的内存表示的一部分没有意义,因为您永远不应该调用任何更改其状态的实体方法。
命令在本质上更接近于数据传输对象,而不是域模型实体。
通常,您系统中的所有实体对象都应该存在于聚合根接口之后,您传递给该接口的参数是 值 。如果领域模型需要一个实体,它可以根据提供的值创建一个实体。