DDD-更新值对象的嵌套集合引发NHibernate异常

DDD-更新值对象的嵌套集合引发NHibernate异常,nhibernate,collections,domain-driven-design,value-objects,Nhibernate,Collections,Domain Driven Design,Value Objects,TLDR版本:我很难让我的DDD域模型与NHibernate一起工作。如果我的值对象本身包含一组值对象,我无法在没有获得NHibernate异常的情况下分配新值,我想知道在这种情况下的最佳实践是什么 较长版本: 假设我有一个实体,它包含一个作为属性的值对象ValueObjectA,它本身包含一组ValueObjectB类型的不同值对象 ValueObjectB仅作为ValueObjectA的属性存在,也就是说,如果myEntity.ValueObjectA==null,ValueObjectB的

TLDR版本:我很难让我的DDD域模型与NHibernate一起工作。如果我的值对象本身包含一组值对象,我无法在没有获得NHibernate异常的情况下分配新值,我想知道在这种情况下的最佳实践是什么

较长版本:

假设我有一个实体,它包含一个作为属性的值对象ValueObjectA,它本身包含一组ValueObjectB类型的不同值对象

ValueObjectB仅作为ValueObjectA的属性存在,也就是说,如果myEntity.ValueObjectA==null,ValueObjectB的存在也没有意义

我已经编写了一些示例代码来说明我的意思,为简洁起见进行了简化

public class Entity
{
    public int Id { get; private set; }
    public ValueObjectA ValueObjectA { get; set; }

    // Constructor: public Entity(ValueObjectA valueObjectA)
}

public class ValueObjectA : IEquatable<ValueObjectA>
{
    public string X { get; private set; }
    public ISet<ValueObjectB> ValueObjectBs { get; private set; }

    // Constructor: public ValueObjectA(string x, ISet<ValueObjectB> valueObjectBs)
    // Implementation of Equals/GetHahcode
}

public class ValueObjectB : IEquatable<ValueObjectB>
{
    public int Y { get; private set; }
    public int Z { get; private set; }

    // Constructor: public ValueObjectB(int y, int z)
    // Implementation of Equals/GetHahcode
}
然而。。。这感觉像是一种代码气味——即使我为Entity.ValueObjectA编写了一个自定义setter,但在设计应该很简单的地方,实现开始变得复杂起来

public class Entity
{
    // ...
    private ValueObjectA valueObjectA;
    public ValueObjectA ValueObjectA
    {
        // get
        set
        {
            // Add/Remove relevant values from ValueObjectA.ValueObjectBs
            valueObjectA = new ValueObjectA(value.X, ValueObjectA.ValueObjectBs);
        }
    }
}

在这种情况下,最佳做法是什么?或者这是我试图做一些违反DDD原则的事情的迹象吗?

你拥有的是一个

您应该使用方法替换实体的公共setter,这些方法具有
通用语言中有意义的名称,检查不变量,并在替换值对象时进行所有必要的清理


虽然看起来事情更复杂,但现在实体完全控制其内部发生的事情,这一事实证明了这一点。您现在拥有了完整的封装。

您很幸运,
NHibernate
对您大喊大叫,否则您可能会在该设计散发出刺鼻气味之前一段时间内侥幸逃脱。我知道贫血区域模型。我的实际域模型使用普遍存在的语言,并在实际对象中维护业务逻辑。(我理解提供的代码是贫乏的,但我想简化它以说明NHibernate异常-否则,它将是TLDR)。我担心的是,当值对象中有引用类型时,很难保持它的简单。假设我有一个值对象、地址和实体Person和Order,分别有一个账单地址和一个送货地址。如果我有定制的逻辑来更新地址,例如,因为它包含一个值对象的集合,如原始示例中所示,我必须在两个实体中放置相同的逻辑,或者引入一个额外的映射/构建器类以保持其干燥。尽管概念设计可能很简单,但感觉实现变得越来越复杂。那是密码的味道吗?
        var valueObjectBs_1 = new HashSet<ValueObjectB>
        {
            new ValueObjectB(1, 2),
            new ValueObjectB(3, 4)
        };

        var valueObjectA_1 = new ValueObjectA("first", valueObjectBs_1);

        var entity = new Entity(valueObjectA_1);

        // Save entity, reload entity

        var valueObjectBs_2 = new HashSet<ValueObjectB>
        {
            new ValueObjectB(1, 2)
        };

        var valueObjectA_2 = new ValueObjectA("second", valueObjectBs_2);

        entity.ValueObjectA = valueObjectA_2;

        // Save entity again
        // NHIBERNATE EXCEPTION
        valueObjectA_1.ValueObjectBs.Remove(new ValueObjectB(3, 4));
        entity.ValueObjectA = new ValueObjectA(valueObjectA_2.X, valueObjectA_1.ValueObjectBs);
public class Entity
{
    // ...
    private ValueObjectA valueObjectA;
    public ValueObjectA ValueObjectA
    {
        // get
        set
        {
            // Add/Remove relevant values from ValueObjectA.ValueObjectBs
            valueObjectA = new ValueObjectA(value.X, ValueObjectA.ValueObjectBs);
        }
    }
}