我在EF Core中配置关系时遇到问题。我遇到了以下例外-
指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREING KEY约束
我已经为这篇文章修剪了实体,但这两个实体都有自己的表。
public class ApplicationSetupTest
{
public Guid Id { get; set; }
public Guid SchemeId { get; set; }
public string Description { get; set; }
public Guid LatestVersionId { get; set; }
public ApplicationSetupVersionTest LatestVersion { get; set; }
public ICollection<ApplicationSetupVersionTest> VersionHistory { get; set; }
}
public class ApplicationSetupVersionTest
{
public Guid Id { get; set; }
public Guid SetupId { get; set; }
public string Data { get; set; }
public string AuditComment { get; set; }
public Guid PreviousVersionId { get; set; }
}
ApplicationSetupTest
类使用LatestVersionId
有效地定义静态数据,CCD_2是导航属性LatestVersion
的关键。
ApplicationSetupVersionTest
类是经过版本控制/审核的数据。其中每一个都有一个SetupId
,将其链接回所引用的ApplicationSetupTest
。
我添加VersionHistory
属性纯粹是为了说明在每个ApplicationSetupTest
上可能有多个ApplicationSetupVersionTest
。我还没有在ApplicationSetupVersionTest
上添加ApplicationSetupTest
,因为这不是我想要的。
我对ApplicationSetupTest
的配置如下:
public class ApplicationSetupEntityConfiguration : IEntityTypeConfiguration<ApplicationSetupTest>
{
public void Configure(EntityTypeBuilder<ApplicationSetupTest> builder)
{
builder.Property(t => t.SchemeId).IsRequired();
builder.Property(t => t.Description).IsRequired();
builder.Property(t => t.LatestVersionId).IsRequired();
builder.HasMany(t => t.VersionHistory)
.WithOne()
.HasForeignKey(t => t.SetupId)
.IsRequired();
builder.HasOne(t => t.LatestVersion)
.WithOne()
.HasForeignKey<ApplicationSetupTest>(t => t.LatestVersionId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
builder.HasOne<Scheme>()
.WithMany()
.HasForeignKey(t => t.SchemeId)
.IsRequired();
}
}
HasMany
->VersionHistory
上的WithOne
定义了当我删除设置时,我应该删除所有版本实体。
因此,我认为第二种配置是需要改变的领域。OnDelete(NoAction)
是在谷歌搜索后添加的,我还尝试删除IsRequired()
,并使LatestVersionId
可以为null。
我希望配置第二个关系,以便LatestVersion
属性可以包含在查询中。
关于如何配置这样的关系,有什么想法吗?还是我在做一些你不会推荐的事情?
(为了简单起见,我将把模型称为Setup
和Version
)。
使用您的一对多配置-
builder.HasMany(t => t.VersionHistory)
.WithOne()
.HasForeignKey(t => t.SetupId)
.IsRequired();
您已经声明Setup
为主端,Version
为从属端,这是正确的。
但是,在Setup
中有一个LatestVersionId
外键,引用Version
,并配置一对一关系-
builder.HasOne(t => t.LatestVersion)
.WithOne()
.HasForeignKey<ApplicationSetupTest>(t => t.LatestVersionId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
尝试将CCD_ 27配置为从属端。我相信你能看出其中的矛盾。
采用以下简化模型-
public class Setup
{
public Guid Id { get; set; }
public string Description { get; set; }
public Version LatestVersion { get; set; }
public ICollection<Version> VersionHistory { get; set; }
}
public class Version
{
public Guid Id { get; set; }
public string Data { get; set; }
// not nullable - every Version must belong to a Setup
public Guid SetupIdHistory { get; set; }
// nullable - not every Version is a latest version
public Guid? SetupIdLatest { get; set; }
}
您可以正确配置它们,将您的关系表示为-
public void Configure(EntityTypeBuilder<Setup> builder)
{
builder.HasMany(p => p.VersionHistory)
.WithOne()
.HasForeignKey(p => p.SetupIdHistory)
.OnDelete(DeleteBehavior.Cascade) // not required, cascading is default
.IsRequired();
builder.HasOne(p => p.LatestVersion)
.WithOne()
.HasForeignKey<Version>(p => p.SetupIdLatest)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}
如果您选择不为一对多关系设置外键,EF将为您创建一个可为null的外键,并使用shadow属性在模型级别管理关系。但是对于一对一关系,必须定义外键。
public class Version
{
public Guid Id { get; set; }
public string Data { get; set; }
// nullable - not every Version is a latest version
public Guid? SetupId { get; set; }
}
public void Configure(EntityTypeBuilder<Setup> builder)
{
builder.HasMany(p => p.VersionHistory)
.WithOne()
.OnDelete(DeleteBehavior.Cascade)
.IsRequired(); // this will have no effect, the FK will be nullable
builder.HasOne(p => p.LatestVersion)
.WithOne()
.HasForeignKey<Model.Version>(p => p.SetupId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}