EF Core Code First——一对一的条件关系

EF Core Code First - one to one conditional relationship

我不确定这种关系是否有名字,所以也许我只是想念它。我在文档中没有找到类似这样的内容。

我有一种多对一的关系,但只有一种关系很重要,所以它有点像一对一,但条件是多方。

装备有多个合约,但最多只有一个激活的合约。

合同总是有一个设备,并且有对设备的引用。那一面工作得很好。我有业务逻辑来防止一个设备的多个合同处于活动状态。

public class EquipmentModel{
    public int Id {get; set;}
    //...other properties
}

public class ContractModel{
    public int Id {get;set;}
    public EquipmentModel Equipment {get;set;}
    public bool Active {get;set;}
    //...other properties
}

这意味着我可以_contracts.Include(x => x.Equipment)并获得合同的设备实体。

但我无法将我的头脑转向另一个方向。我不想将所有联系人都放在设备实体上,我不需要它们,这似乎有点过分了。

我想我可以将 Contract 实体放在 Equipment 模型上并手动管理业务逻辑中的关系,但我希望 Entity Framework 有更好的方法来指定它。

我也可以撤回所有合同并使用一些业务逻辑过滤到活动合同,但这也不太理想。

public IEnumerable<ContractModel> Contracts {get;set;}

理想情况下,我希望能够执行 _equipment.Include(x => x.ActiveContract) 之类的操作,并自动拥有一份带有 Active == true 的合同。这是 EF Core 中存在的模式吗?

该设计最简单的方法是使用 Filtered Include,

_equipment.Include(x => x.Contracts.Where(c => c.Active))

您可以通过在 DbContext 上创建一个方法来重用此表达式,returns 带有 Include 的基本查询,例如

 public IQueryable<Equipment> GetEquipment() => this.Set<Equipment>().Include(x => x.Contracts.Where(c => c.Active));

可以通过运行查询前的调用代码进一步过滤,例如

var equips = db.GetEquipment().Where(e => e.Name == equipName).ToList();

如果您对此有强烈的感觉,您甚至可以省略 DbContext 上的 DbSet<Equipment> 属性(在 OnModelCreating 中将设备注册为实体),并将其替换为

public IQueryable<Equipment> Equipment => this.Set<Equipment>().Include(x => x.Contracts.Where(c => c.Active));