【问题标题】:Aggregate root creating child entities with new GUIDS聚合根创建具有新 GUIDS 的子实体
【发布时间】:2014-11-20 09:36:54
【问题描述】:

我通常使用 nHibernate 为我的实体生成唯一 ID...但我正在考虑在代码中生成它们?考虑以下示例:(如果我做错了什么,请指出,因为我是 DDD 新手):

这些都是属于同一个程序集的所有类,即我的域模型。

public interface AggregateRootState
{
    bool CanAddChild(); 
    bool CanModifyChild(); 
    bool CanDeleteChild(); 
}

public class AggregateRoot
{
    private AggregateRootState aggregateRootState; 

    public IList<ChildEntity> ChildEntityList {get; internal set;}

    public bool CanAddChild()
    {
        return aggregateRootState.CanAddChild(); 
    }

    public void AddChild(ChildEntityParameters childEntityParameters)
    {
        if (!CanAddChild())
            throw new NotImplementedException("aggregate root not in correct state."); 

        ChildFactory.CreateChildEntity(childEntityParameters);
    }

    public bool CanModifyChild()
    {
        return aggregateRootState.CanModifyChild(); 
    }

    public void ModifyChild(ChildEntityParameters childEntityParameters)
    {

        if (!CanModifyChild())
            throw new NotImplementedException("aggregate root not in correct state.");

        ChildEntity childEntity = ChildEntityList.First(c => c.Id == childEntityParameters.Id); 
        childEntity.Property1 = childEntityParameters.Property1; 
        childEntity.Property2 = childEntityParameters.Property2; 
    }

    public bool CanDeleteChild()
    {
        return aggregateRootState.CanDeleteChild(); 
    }

    public void DeleteChild(Guid Id)
    {
        if (!CanDeleteChild())
            throw new NotImplementedException("aggregate root not in correct state");

        ChildEntityList.Remove(ChildEntityList.First(c => c.Id == Id));
    }

    public void Validate()
    {
        //code to validate the object and ensure it is in a savable state. 
    }
}

public class ChildEntityParameters
{
    public Guid Id {get; set;}
    public string Property1 {get; set;}
    public string Property2 {get; set;}
}

public class ChildEntity
{
    internal ChildEntity() { }
    public Guid Id {get; set;}
    public string Property1 {get; internal set;}
    public string Property2 {get; internal set;}
}

internal static class ChildFactory
{
    public static void CreateChildEntity(ChildEntityParameters childEntityParameters)
    {
        ChildEntity childEntity = new ChildEntity(); 
        childEntity.Property1 = childEntityParameters.Property1; 
        childEntity.Property2 = childEntityParameters.Property2; 
    }
}

我的服务层将如下所示:

//for simplicity I have arguments rather than using the request / response pattern. 
public class ServiceLayer
{
    public void AddChildEntity(Guid aggregateRootId, string string1, string string2)
    {
        AggregateRoot aggregateRoot = aggregateRootRepository.FindBy(aggregateRootId);
        ChildEntityParameters childEntityParameters = new ChildEntityParameters();
        childEntityParameters.Property1 = string1;
        childEntityParameters.Property2 = string2;
        aggregateRoot.AddChild(childEntityParameters); 
        aggregateRoot.Validate(); //will throw exception if there is something wrong. 
        aggregateRootRepository.Save(aggregateRoot);
    }
}

现在这一切都很好。但是问题是如果我想将新创建的 ChildEntity 的 ID 返回到表示层怎么办?目前是不可能的。我将不得不返回整个对象图。我能想到的唯一选择是对我的代码进行以下更改:

internal static class ChildFactory
{
    public static void CreateChildEntity(ChildEntityParameters childEntityParameters)
    {
        ChildEntity childEntity = new ChildEntity(); 
        **childEntity.Id = Guid.NewGuid();**  
        childEntity.Property1 = childEntityParameters.Property1; 
        childEntity.Property2 = childEntityParameters.Property2; 
    }
}

public class ServiceLayer
{
    public **Guid** AddChildEntity(Guid aggregateRootId, string string1, string string2)
    {
        **Guid Id;** 
        AggregateRoot aggregateRoot = aggregateRootRepository.FindBy(aggregateRootId);
        ChildEntityParameters childEntityParameters = new ChildEntityParameters();
        childEntityParameters.Property1 = string1;
        childEntityParameters.Property2 = string2;
        **Id = aggregateRoot.AddChild(childEntityParameters);** 
        aggregateRoot.Validate(); //will throw exception if there is something wrong. 
        aggregateRootRepository.Save(aggregateRoot);
        return Id; 
    }
}

这是错的吗?还是完全没问题?如果有人能澄清一下就好了!

【问题讨论】:

    标签: design-patterns nhibernate domain-driven-design business-logic aggregateroot


    【解决方案1】:

    Vaughn Vernon 的出色book 建议创建实体的适当策略是它们完全形成了一个身份,而不是在瞬态状态下创建,我想。因此,我认为通过确保孩子使用它的 id 进行创建,您是正确的。

    这也解决了一个棘手的小问题,即获取瞬态对象的哈希码并不总是为等效的持久对象返回相同的哈希码。

    【讨论】:

    • 我将不得不查看那本书,因为它似乎被相当多地引用了。所以你建议我应该在为我的所有实体创建对象时生成 ID?包括总根?在发布原始问题后,我做了一些进一步的研究,发现如果你指定一个 ID,那么 nHibernate 不知道是插入还是更新记录?这只是更改 nhibernate 中的配置的问题吗?
    • 你不能让NH通过Save()为你生成ID吗?或者更改您的映射以使 id = 已分配?
    • 我现在很困惑。如果我让 NH 通过 Save() 为我生成 ID,我又回到了原来的问题,因为我无法获取新创建的子实体的 ID?所以我想我必须更改映射以便 id = 分配。这里提到了这个问题:stackoverflow.com/questions/5048728/… 但我真的没有看到替代方案?错误的设计决策根据:nhforge.org/doc/nh/en/…
    【解决方案2】:

    这最终是我的解决方案。执行保存时,将为子对象填充 ID。因为我有对子对象的引用,所以我可以返回 ID。作为 DDD 的新手,我不知道您可以传递子实体……但在进一步阅读之后,我偶然发现了 Eric Evans 的以下规则:

    根实体可以将对内部实体的引用传递给其他对象,但这些对象只能暂时使用它们,并且可能不会保留引用。

    public class ServiceLayer
    {
        public **Guid** AddChildEntity(Guid aggregateRootId, string string1, string string2)
        {
            **ChildObject obj;** 
            AggregateRoot aggregateRoot = aggregateRootRepository.FindBy(aggregateRootId);
            ChildEntityParameters childEntityParameters = new ChildEntityParameters();
            childEntityParameters.Property1 = string1;
            childEntityParameters.Property2 = string2;
            **obj = aggregateRoot.AddChild(childEntityParameters);** 
            aggregateRoot.Validate(); //will throw exception if there is something wrong. 
            aggregateRootRepository.Save(aggregateRoot);
            return obj.Id; 
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多