【发布时间】:2023-04-05 20:47:01
【问题描述】:
在观看了 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;
}
}
所以这个领域模型中包含一些规则:
- 会员必须有名字和姓氏
- 优惠数量不能在外面更改
- 会员负责创建新报价,计算其价值和分配
如果尝试将其映射到某些 ORM,如 Entity Framework 或 NHibernate,它将无法正常工作。
那么,使用 ORM 将这种模型映射到数据库的最佳方法是什么?
例如,如果没有 setter,我如何从 DB 加载 AssignedOffers?
对我来说唯一有意义的是使用命令/查询架构:查询总是使用 DTO 作为结果,而不是域实体,并且命令是在域模型上完成的。此外,事件溯源非常适合域模型上的行为。但这种 CQS 架构可能并不适合每个项目,尤其是棕地。还是不行?
我知道这里有类似的问题,但找不到具体的例子和解决方案。
【问题讨论】:
-
我刚刚看了同样的视频,我也在想同样的事情。您如何看待在构造函数中传递一个 poco,并且在 Member 类上具有一个只读属性以返回该 poco 的克隆?这样您就可以将数据传入和传出域对象,以便将其持久化或传递。
-
对象快照之类的东西?它可能会起作用,但也需要一些黑客攻击才能使其与 ORM 工具一起使用。我个人认为没有任何简单的方法,它会带来很多抽象和概括,你必须在整个应用程序开发过程中与之抗争。事件溯源是 IMO 的唯一途径
-
其实我刚刚看了这个视频,也在想同样的事情;这是否意味着您需要一组 DTO/POCO 对象用于 ORM 水合的数据/持久层,然后使用 AutoMapper 之类的映射器映射到域对象?类似的事情发生在存储库中吗?看起来像 EF Code First 这样的 ORM 需要一个带有 getter 和 setter 的 POCO。
-
@Abe 是的,在我看来 EF 模型应该低于域模型,并在保存或加载内容时使用 AutoMapper 魔法。此外,对于 UI,还有另一组 ViewModel,再次从域模型映射,而不是 EF 模型。业务逻辑应该在那些领域模型中,而不是在你可以随处可见的SomethingManager 类中。恕我直言:)
-
酷!您是否觉得编写这么多映射代码很乏味/繁重? EF 到域模型,然后域到 MVC 视图模型......也可能有域到 WCF 合同等......看起来你可以 AutoMapper 有一个 ConstructUsing 方法,可以让你创建一个新对象而不是使用 getter 和 setter领域模型如stackoverflow.com/questions/2239143/…
标签: c# .net architecture orm domain-driven-design