使用新GUID聚合根创建子实体

时间:2014-11-20 09:36:55

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

我通常使用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; 
    }
}

这是错的吗?还是完全没问题?如果有人能说清楚会好的!

2 个答案:

答案 0 :(得分:1)

Vaughn Vernon的优秀book表明,创建实体的合适策略是它们以完整形式到达,而不是在瞬态创建,我想。因此,我认为通过确保孩子用它的身份来创造你是正确的。

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

答案 1 :(得分:0)

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

  

根实体可以手动引用其他对象的内部ENTITIES,但这些对象只能暂时使用它们,并且可能无法保留引用。

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; 
    }
}