我试图理解 DDD 概念,当我想更新作为与根实体关联的集合的一部分的实体时偶然发现。我试图从根实体强制执行不变量,但我发现有一种方法可以在将验证保存到数据库之前绕过验证。
基于 DDD 规则之一实现了域模型:
根实体具有全局身份,并最终负责检查不变量。
我有一个 Me 类根实体,它有一个名为 Friends 的实体集合。有最好的朋友,只是朋友,工作朋友等朋友类型
不变: friends 集合可以包含任意数量的 Just Friend 和 Work Friend,但只能包含一个 Best friend。
public class Me : Entity, IAggregateRoot
{
public string Name {get; }
private List<Friend> friends;
public IReadonlyCollection<Friend> Friends => friends;
public Me(string name)
{
Name = name;
friends = new List<Friend>();
}
public void AddFriend(string name, string type)
{
//Enforcing invariant
if(CheckIfBestFriendRuleIsSatisfied(type))
{
Friend friend = new Friend(name, type);
friends.Add(friend);
}
else
throw new Exception("There is already a friend of type best friend.");
}
public void UpdateFriend(int id, string name, string type)
{
//Enforcing invariant
if(CheckIfBestFriendRuleIsSatisfied(id, type))
{
Friend friend = firends.First(x => x.Id == id);
friend.SetType(type);
friend.SetName(name);
}
else
throw new Exception("Cannot update friend.");
}
}
public class Friend : Entity
{
public string Name {get; }
public string Type {get; }
public Friend(string name, string type)
{
Name = name;
Type = type;
}
public void SetType(string type)
{
Type = type;
}
public void SetName(string name)
{
Name = name;
}
}
场景:我的根实体在集合中有两个朋友,一个是最好朋友类型,另一个是朋友类型。现在,如果您尝试将“justfriend”实体的类型从“Just Friend”更改为“ Best Friend ”,代码不应允许并抛出异常,因为这是违反业务规则的。
在更新朋友时强制执行不变的正常实现。
public void DomainService_UpdateFriend() { var me = repo.GetMe("1"); me.UpdateFriend(2,"john doe","Best Friend"); //Throws Exception repo.SaveChanges(); }业务规则绕过实现
public void DomainService_UpdateFriend() { var me = repo.GetMe("1"); var friend = me.Friends.First(x => x.Id == 2); friend.SetType("Best Friend"); // Business rule bypassed friend.SetName("John Doe"); repo.SaveChanges(); }
这让我想到了问题:
- 模型上的设计是错误的吗?
如果是,它是怎么错的,正确的实现应该是什么?
如果不是,那么这是否违反了上述 DDD 规则? 以下将是正确的实施
public class Me : Entity, IAggregateRoot { ...Properties ...ctor ...AddFriend public void UpdateFriend(int id, string name, string type) { Friend friend = firends.First(x => x.Id == id); if(friend != null) { friend.SetNameAndType(name,type, this);//Passing Me root entity } else throw new Exception("Could not find friend"); } } public class Friend : Entity { ...Properties ...ctor //passing root entity as parameter or set it thru ctor public void SetupNameAndType(string name, string type, Me me) { if(me.CheckIfBestFriendRuleIsSatisfied(id, type)) { Name = name; Type = type; } else throw new Exception(""); } }强制不变/验证的位置从将实体添加到集合与更新集合中的实体不同?这是在 Addfriend() 正确时验证,但在 UpdateFriend() 时不正确。
这是否提醒我们 DDD 中的另一条规则,即 当对聚合边界内的任何对象的更改被提交时,必须满足整个聚合的所有不变量。
这个实现看起来如何?
使用规范/通知模式并验证域服务上的域模型是否解决了这个问题?
当有多个上下文或模型的多个状态时,使用规范模式会更合适。但是如果没有多个上下文和状态呢?
虽然我很欣赏各种答案,但我正在寻找代码实现以使其正确。我见过很多关于 SO 的问题,但没有一个显示代码实现。