我不熟悉域驱动设计,最近我开始为项目创建域模型。我还没有决定使用ORM(虽然我可能会选择NHibernate)而且我目前正在尝试确保我的Value Objects应该就是这样。
我有一些VO除了封装“喜欢”术语之外几乎没有任何行为,例如:
public class Referral {
public Case Case { get; set; } // this is the a reference to the aggregate root
public ReferralType ReferralType { get; set; } // this is an enum
public string ReferralTypeOther { get; set; }
} // etc, etc.
这个特殊课程提到了两个级别的“案例”,所以如果我要访问推荐,我可以去:case.social.referral(案例,社交和推荐都是类,有一个案例中的单个社交,并且在社交内部有一个单一的引用)。现在,当我输入它时我正在查看它,我认为我在推荐中不需要一个案例,因为它可以通过社交实体访问,对吗?
现在,毫无疑问,我认为这应该是一个VO,而我计划用来将其保存到数据库的方法是让NHibernate为它分配一个代理标识符(我仍然不是太清楚,如果有人可以请详细说明它也会帮助我,因为我不知道代理标识符是否要求我已经在我的VO中有一个Id或者它是否可以在没有一个的情况下运行)和/或protected Id属性,不会在Referral类之外公开(仅用于持久保存到DB)。
现在谈谈我的标题问题:VO中是否应该有一个集合(在我的情况下是一个List)?我只能将其视为数据库中的一对多关系,但由于没有身份,因此使类成为实体似乎不够。以下是代码:
public class LivingSituation {
private IList<AdultAtHome> AdultsAtHome { get; set; }
public ResidingWith CurrentlyResidingWith { get; set } // this is an enum
} // etc, etc.
此类目前没有Id,而AdultsAtHome类只有内在类型(string,int)。所以我不确定这是否应该是一个实体,或者它是否可以作为VO保留,我只需要使用自己的表和私有/受保护的Id字段将我的ORM配置为使用1:m关系,以便ORM可以持久保存到DB。
另外,我应该为每个课程使用规范化表格吗?我想我只需要为每个类使用一个表,当有可能将类的多个实例分配给实体或值对象时和/或有可能与这些对象中的某些对象具有集合1:m的关系。对于具有内部类型但具有嵌套类型的某些值对象使用单个表我没有问题我认为使用规范化表是有利的。对此有何建议?
对于多个问题如此冗长而感到抱歉:
1)我的值对象是否需要代理标识符(例如NHibernate)?
2)如果#1为是,那么这是否需要私有/保护,以便我的值对象“保持”概念中的值对象?
3)值对象可以具有其他值对象(例如,列表)还是构成实体? (我认为这个问题的答案是否定的,但在进一步研究之前,我更愿意确定。)
4)我是否需要从聚合根的几个级别的值对象中引用聚合根? (我不认为我这样做,这可能是我在编写模型时的疏忽,有人同意吗?)
5)对于某些事情使用规范化表是否可以(例如嵌套类型和/或具有集合作为属性的类型,无论如何都需要自己的表用于1:m关系),同时让ORM执行映射更简单的值对象到属于我的实体的同一个表?
再次感谢。
答案 0 :(得分:9)
1)是 - 如果您将VO存储在自己的表格中
2)如果你可以使用私人/受保护的ID属性,那就太好了。或者,您可以使用显式接口来“隐藏”ID属性。
但是,在阅读您的问题时,您是否建议看到ID属性的开发人员会自动认为该对象是实体?如果是这样,他们需要(重新)训练。
3)是的,可以,但有以下限制:
另外,请考虑一下:VOs 不应该坚持下去。每次需要时重新创建整个VO是否容易/有效?如果没有,请将其设为实体。
4)取决于您希望如何实施汇总锁定。如果您想使用Ayende's solution,答案是肯定的。否则,您需要一种机制来将对象图遍历回聚合根。
5)是的。不要忘记DDD Persistence Ignorant (在理想世界中!)。
我认为推介应该是实体。想象一下这些对话:
对话1:
对话2:
对话1表明推荐是实体,而对话2表明它是VO。
还有一件事:Referral.ReferralType
在其生命周期中是否会发生变化(还有另一个暗示它应该是实体)?如果没有改变,请考虑使用多态,让NH处理它。
希望有所帮助!