Entity framework core 同一个表的多个关系,EF Core中有一个必需关系,其他关系可选

Entity framework core 同一个表的多个关系,EF Core中有一个必需关系,其他关系可选,entity-framework-core,foreign-keys,relational-database,Entity Framework Core,Foreign Keys,Relational Database,我有一个名为Provider的表,它与另一个表State有三个关系。在这些关系中,一个是必需的,另外两个是可选的。请参见下图中的关系: 以下是实体以及每个实体的fluent配置 供应商 公共类提供程序 { 公共int Id{get;set;} [必需] public int PrimaryStateId{get;set;} 公共虚拟状态PrimaryState{get;set;} 公共int?BillingStateId{get;set;} 公共虚拟状态BillingState{get;set

我有一个名为
Provider
的表,它与另一个表
State
有三个关系。在这些关系中,一个是必需的,另外两个是可选的。请参见下图中的关系:

以下是实体以及每个实体的fluent配置

供应商
公共类提供程序
{
公共int Id{get;set;}
[必需]
public int PrimaryStateId{get;set;}
公共虚拟状态PrimaryState{get;set;}
公共int?BillingStateId{get;set;}
公共虚拟状态BillingState{get;set;}
public int?ShippingStateId{get;set;}
公共虚拟状态ShippingState{get;set;}
}
类ProviderConfig:IEntityTypeConfiguration
{
公共void配置(EntityTypeBuilder实体)
{
entity.HasOne(x=>x.PrimaryState)
.WithMany(x=>x.ProvidersPrimary)
.IsRequired(正确)
.OnDelete(DeleteBehavior.Restrict);
entity.HasOne(x=>x.BillingState)
.WithMany(x=>x.ProvidersBilling)
.IsRequired(假)
.OnDelete(DeleteBehavior.SetNull);
entity.HasOne(x=>x.ShippingState)
.WithMany(x=>x.ProvidersShipping)
.IsRequired(假)
.OnDelete(DeleteBehavior.SetNull);
}
}
陈述
公共类状态
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection ProvidersPrimary{get;set;}=new List();
公共虚拟ICollection提供程序sbilling{get;set;}=new List();
公共虚拟ICollection ProvidersShipping{get;set;}=new List();
}
类StateConfig:IEntityTypeConfiguration
{
公共void配置(EntityTypeBuilder实体)
{
Property(x=>x.Name).IsRequired();
entity.HasIndex(x=>x.Name).IsUnique();
}
}
如您所见,我想为
PrimaryState
设置
DeleteBehavior.Restrict
,为其他两个关系设置
DeleteBehavior.SetNull
。但是,这会在更新数据库时抛出错误,并显示以下消息:

在表“Provider”上引入外键约束“FK\u Provider\u State\u ShippingStateId”可能会导致循环或多个级联路径。指定“在删除时不执行操作”或“在更新时不执行操作”,或修改其他外键约束。 无法创建约束或索引。请参阅前面的错误

但是,如果我去掉其中一个可选关系,它就可以正常工作。也就是说,当我有一个必需关系和一个可选关系时,它工作,但当我有一个必需关系和两个可选关系时,它不工作。另外,如果我从可选关系中去掉
OnDelete(DeleteBehavior.SetNull)
,它也可以正常工作,但是在数据库中,外键
BillingStateId
的删除规则最终是
Set Null
,而
ShippingStateId
的删除规则是
No Action
。不知道为什么两个配置类似的可选关系会有所不同

问题:

  • 为什么
    更新数据库
    会因该错误而失败?我不明白循环或多个级联路径是如何产生的
  • 为什么要摆脱OnDelete(DeleteBehavior.SetNull)为一个可选关系创建一个带有
    Set Null
    delete规则的外键,而为另一个可选关系创建
    无操作
  • 配置此关系的正确方法是什么?也就是说,一个必需关系和两个可选关系,可选关系的外键的删除规则应为
    Set Null

  • VS解决方案链接:

    关于#1,询问SqlServer开发团队为什么会有这种限制,为什么这么多年都不愿意修复它。@IvanStoev那么你是说这是SqlServer本身的限制,与EF Core无关?这有文件记录吗?感谢您对btwYes的深入了解,该异常肯定来自SQL Server,而不是EF。@IvanStoev是否有任何关于如何实现所需目标的建议?使用
    DeleteBehavior.ClientSetNull
    并处理
    State
    删除客户端,例如,使用相关数据加载
    var stateTodelet=db.Set()。包括(x=>x.ProvidersBilling)。包括(x=>x.ProvidersShipping)。首先或默认(…);
    然后删除
    db.Remove(stateTodele)
    关于#1,询问SqlServer开发团队为什么会有这样的限制,为什么这么多年来都不愿意修复它。@IvanStoev那么你是说这是SqlServer本身的限制,与EF Core无关?这是否有文档记录?感谢btwYes的洞察,这个例外肯定来自SqlServer,而不是EF。@IvanStoev关于如何实现我想要的目标有什么建议吗?使用
    DeleteBehavior.ClientSetNull
    并处理
    State
    删除客户端,例如加载相关数据
    var stateToDelete=db.Set().Include(x=>x.providersbiling).Include(x=>x.ProvidersShipping).首先是默认值(…);
    然后删除
    db.Remove(stateTodelet);
    public class Provider
    {
        public int Id { get; set; }
    
        [Required]
        public int PrimaryStateId { get; set; }
        public virtual State PrimaryState { get; set; }
    
        public int? BillingStateId { get; set; }
        public virtual State BillingState { get; set; }
    
        public int? ShippingStateId { get; set; }
        public virtual State ShippingState { get; set; }
    }
    
    class ProviderConfig : IEntityTypeConfiguration<Provider>
    {
        public void Configure(EntityTypeBuilder<Provider> entity)
        {
            entity.HasOne(x => x.PrimaryState)
                  .WithMany(x => x.ProvidersPrimary)
                  .IsRequired(true)
                  .OnDelete(DeleteBehavior.Restrict);
    
            entity.HasOne(x => x.BillingState)
                  .WithMany(x => x.ProvidersBilling)
                  .IsRequired(false)
                  .OnDelete(DeleteBehavior.SetNull);
    
            entity.HasOne(x => x.ShippingState)
                  .WithMany(x => x.ProvidersShipping)
                  .IsRequired(false)
                  .OnDelete(DeleteBehavior.SetNull);
        }
    }
    
    public class State
    {
        public int Id { get; set; }
        public string Name { get; set; }
    
        public virtual ICollection<Provider> ProvidersPrimary { get; set; } = new List<Provider>();
        public virtual ICollection<Provider> ProvidersBilling { get; set; } = new List<Provider>();
        public virtual ICollection<Provider> ProvidersShipping { get; set; } = new List<Provider>();
    }
    
    class StateConfig : IEntityTypeConfiguration<State>
    {
        public void Configure(EntityTypeBuilder<State> entity)
        {
            entity.Property(x => x.Name).IsRequired();
            entity.HasIndex(x => x.Name).IsUnique();
        }
    }