问题描述
想象一下,有一个像这个例子这样的实体:
public class Thing
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
我该如何添加一个矛盾语,以便所有Thing
中只有一个具有特定名称的true
可以用于IsActive
? / p>
换句话说,我们可以有多个具有相同名称的Thing
,但在任何给定时间只能有一个IsActive
的{{1}}-其他人需要拥有true
的{{1}}。因此,如果我们要添加或更新一个,则需要检查false
的新值为IsActive
是否不会造成“冲突”。
这有可能吗?
解决方法
一种选择是采取行动来更改实体状态,而不是公共设置者。例如,在大多数情况下,我的实体与DbContext和诸如Repository类之类的对象一起驻留在Domain程序集中。 “事物”将驻留在容器实体下以进行唯一关联。
public class Thing
{
public int Id { get; internal set;}
public string Name { get; internal set; }
public bool IsActive { get; internal set; }
}
public class Container
{
public int Id { get; internal set; }
public virtual ICollection<Thing> Things { get; internal set; } = new List<Thing>();
public void AddThing(string name,bool isActive = true)
{
var existingActiveThing = Things.SingleOrDefault(x => x.Name == name && x.IsActive);
if(isActive && existingActiveThing != null)
existingActiveThing.IsActive = false;
var newThing = new Thing { Name = name,IsActive = isActive };
Things.Add(newThing);
}
public void ActivateThing(int thingId)
{
var thing = Things.Single(x => x.Id == thingId);
if(thing.IsActive)
return; // Nothing to do.
var existingActiveThing = Things.SingleOrDefault(x => x.Name == thing.Name && x.IsAcitve);
if (existingActiveThing != null)
existingActiveThing.IsActive = false;
thing.IsActive = true;
}
// And so forth for instance Renaming a Thing or other allowed actions.
}
容器可以是一个包含实体,或者可以将这些操作封装在用Things集合初始化的域级别服务类中,或者如果Things是顶级实体则可以访问DbContext。设置器被标记为“内部”,要求使用域级别的方法来改变状态,而不是通过设置器进行任意更新。如果要在多个实体或多个字段之间执行验证以确保实体在每个时间点的状态都是有效的,则此技术很有用。 (即,将地址字段更新为一组要验证的值,而不是一次更新一个字段,您可以在其中更改“国家/地区”,或者将实体设置为无法通过验证的无效值组合)