具有行为和ORM的丰富域模型

Hrv*_*udo 17 .net c# architecture orm domain-driven-design

在观看了来自Jimmy Bogard(http://ndcoslo.oktaset.com/Agenda)的NDC12演示文稿"Crafting Wicked Domain Models"之后,我在徘徊如何坚持这种域模型.
这是演示文稿中的示例类:

public class Member
{
    List<Offer> _offers;

    public Member(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
        _offers = new List<Offer>();
    }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public IEnumerable<Offer> AssignedOffers { 
        get { return _offers; }
    }

    public int NumberOfOffers { get; private set; }

    public Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc)
    {
        var value = valueCalc.CalculateValue(this, offerType);
        var expiration = offerType.CalculateExpiration();
        var offer = new Offer(this, offerType, expiration, value);
        _offers.Add(offer);
        NumberOfOffers++;
        return offer;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,此域模型中包含一些规则:
- 成员必须具有名字和姓氏
- 不能在外部更改要约数量
- 成员负责创建新要约,计算其价值和分配

如果尝试将此映射到某些ORM(如Entity Framework或NHibernate),则无法正常工作.那么,使用ORM将这种模型映射到数据库的最佳方法是什么?
例如,如果没有setter,如何从DB加载AssignedOffers?

只有对我有意义的是使用命令/查询架构:查询总是使用DTO作为结果,而不是域实体,并且命令在域模型上完成.此外,事件采购非常适合域模型上的行为.但是这种CQS架构并不适合每个项目,特别是棕色区域.或不?

我在这里知道类似的问题,但找不到具体的例子和解决方案.

Dav*_*ers 11

这实际上是一个非常好的问题,我已经考虑过了.创建完全封装的正确域对象(即没有属性设置器)并使用ORM直接构建域对象可能很困难.

根据我的经验,有3种方法可以解决这个问题:

  • 正如Luka已经提到的,NHibernate支持映射到私有字段,而不是属性设置器.
  • 如果使用EF(我认为不支持上述内容),您可以使用memento模式将状态恢复到域对象.例如,您使用实体框架填充您的域实体接受的"memento"对象来设置其私有字段.
  • 正如您所指出的,将CQRS与事件源一起使用可以消除此问题.这是我制作完美封装的域对象的首选方法,它还具有事件源的所有附加好处.


Luk*_*uka 1

对于AssignedOffers:如果您查看代码,您会发现AssignedOffers从字段返回值。NHibernate 可以像这样填充该字段:Map(x => x.AssignedOffers).Access.Field()。

同意使用 CQS。