Entity Framework - 每个不同的字符串 属性 对于其他 属性 只有一个可能的 "true" 值

Entity Framework - per distinct string property only have one possible "true" value for other property

想象一下有一个像这个例子这样的实体:

public class Thing
{
    public int Id { get; set; }

    public string Name { get; set; }

    public bool IsActive { get; set; }
}

我如何添加一个约束,以便只有 ONE 具有特定名称的所有 Thing 可以有 true for IsActive?

换句话说,我们可以有多个同名的 Thing,但在任何给定时间,只有一个可以有一个 IsActive,即 true - 其他人需要false 对应 IsActive。因此,如果我们要添加或更新一个,它需要检查新值是否为 true for IsActive,这样就不会产生“冲突”。

这有可能吗?

一种选择是采用更改实体状态的操作而不是 public setter。例如,在大多数情况下,我的实体与 DbContext 和 Repository classes 之类的东西一起驻留在域程序集中。 “事物”将驻留在容器实体下以进行唯一关联。

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.
}

容器可以是包含实体,或者这些操作可以封装在域级服务 class 中,如果事物是​​ top-level 实体,则可以使用事物集合初始化或访问 DbContext。 setter 被标记为 Internal 以要求使用域级方法来改变状态,而不是通过 setter 进行任意更新。如果您希望跨多个实体或多个字段强制执行验证以确保每个时间点的实体状态都有效,则此技术很有用。 (即将地址字段更新为一组要验证的值,而不是一次一个字段,您可以在其中更改国家/地区等,使实体处于无法通过验证的无效值组合)