【问题标题】:Am I designing and constructing my value objects correctly?我是否正确地设计和构建了我的价值对象?
【发布时间】:2018-03-07 13:39:40
【问题描述】:

如果这个问题不清楚,请提前道歉。请告诉我要进行哪些更改以使其成为更好的问题。

我目前正在维护一个 C# WinForm 系统,我正在尝试学习和使用 DDD 和 CQRS 原则。 Vaughn Vernon 的实施领域驱动设计 是我的主要 DDD 参考文献。

该系统当前使用利用数据感知控件的遗留代码。 在资产库存上下文中,我设计了我的聚合根Asset,它由多个值对象组成,这些值对象是系统中的标准条目:

在这种情况下,我正在尝试实现一个用户可以手动向系统注册Asset 的用例。

我当前的实现如下:

从表示层:

加载RegisterAssetForm.cs 时,它会通过数据感知控件加载GroupItemName 等现有的标准条目列表,所有这些列表都由具有id: intname: string 列的数据行组成。

当用户选择所需的ItemNameGroupPropertyLevelDepartmentCategory,然后点击保存,执行命令:

RegisterAssetForm.cs强>

...
AssetInventoryApplicationService _assetInventoryServ;
...
void btnSave_Click(object sender, EventArgs e)
{
    int itemNameId = srcItemName.Value // srcItemName is a custom control whose Value = datarow["id"]
    int groupId = srcGroup.Value;
    string categoryId = srcCategory.Value;
    string departmentId = srcDepartment.Value;
    string propLvlId = srcPropLevel.Value;
    ...
    RegisterAssetCommand cmd = new RegisterAssetCommand(itemNameId, groupId, categoryId, departmentId, propLvlId);

    _assetInventoryServ.RegisterAsset(cmd);
    ...
}

从应用层:

AssetInventoryApplicationService 依赖于域服务。

AssetInventoryApplicationService.cs

...
IAssetRepository _assetRepo;
...
public void RegisterAsset(RegisterAssetCommand cmd)
{
    ...
    AssetFactory factory = new AssetFactory();
    AssetID newId = _assetRepo.NextId();
    Asset asset =  factory.CreateAsset(newId, cmd.ItemNameId, cmd.PropertyLevelId,
        cmd.GroupId, cmd.CategoryId, cmd.DepartmentId);

   _assetRepo.Save(asset);
    ...
}

从域层:

AssetFactory.cs //不是我的最终实现

...
public class AssetFactory
{
...
    public Asset CreateAsset(AssetID id, int itemNameId, int propLvlId, int groupId, int categoryId, int departmentId)
    {
        ItemName itemName = new ItemName(itemNameId);
        PropertyLevel propLvl = new PropertyLevel(propLvlNameId);
        Group group = new Group(groupNameId);
        Category category = new Category(categoryNameId);
        Department department = new Department(departmentNameId);

        return new Asset(id, itemName, propLvl, group, category, deparment);   
    }
...
}

填充我的值对象的示例表

+------------+--------------+
| CategoryID | CategoryName |
+------------+--------------+
|          1 | Category1    |
|          2 | Category2    |
|          3 | Category3    |
|          4 | Category4    |
|          5 | Category5    |
+------------+--------------+

我知道域模型必须是持久性无知的,这就是为什么我打算在 Layer Supertype 中使用 surrogate identites(id 字段)和我的 valueobject 来将持久性问题与域。

区分我的值对象的主要属性是它们的名称

从表示层,我通过命令将标准条目值作为与主键对应的整数 id 发送到使用域服务的应用层。

问题

    * 创建命令时传递标准条目的 id 是否合适,还是应该传递字符串名称?
    * 如果传入id,如果需要name,如何构造标准的入口值对象?
    * 如果 name 被传递,我需要从存储库中找出 id 吗?
    * 或者我只是错误地设计了我的标准条目值对象?

感谢您的帮助。

【问题讨论】:

标签: domain-driven-design cqrs value-objects


【解决方案1】:

在我看来,您可能混淆了值对象和实体。

本质的区别是实体需要一个 ID,而 VO 是一个东西(而不是一个特定的东西)。 CRM 中的电话号码可能是 VO。但如果您是一家电话公司,它很可能是一个实体。

我在这篇文章中有一个 VO 示例,您可能会发现它对您有所帮助 - you can get it here

更具体地回答您的“问题”:

  1. 如果您正在创建某个实体,那么将 id 传递给命令可能是有利的。这样你就已经知道 id 是什么了。
  2. 您不应创建无效的值对象。
  3. 为什么不能传递姓名和ID?再次 - 不确定这是否与值对象相关
  4. 认为你设计的不正确。但我不能确定,因为我不知道您的具体域。

希望这会有所帮助!

【讨论】:

  • 其实我的主域是资产实体。值对象(组等)描述了我的资产实体,并且在构建它时是必需的。是的,值对象有一个 id,但这并不意味着它是它的身份。虽然我的数据模型确实需要这些 id,但这就是为什么我想使用 DDD 书中描述的 Layer 超类型。 1.我正在创建一个价值对象而不是实体,但我在这里理解你的观点。 2 & 4. 这很有帮助,我可能需要重新设计我的模型。 3. 在命令中传递/包含的参数方面是否有最佳实践?
猜你喜欢
  • 2020-10-16
  • 2017-07-06
  • 2018-05-27
  • 2019-08-08
  • 1970-01-01
  • 2012-03-02
  • 2011-10-19
  • 2012-06-30
  • 2011-12-07
相关资源
最近更新 更多