实体框架核心 - 不需要的删除级联

Tom*_*ski 4 c# entity-framework-core .net-core

我有实体框架核心,它执行我不想要的额外删除.

模型定义:我有两个实体TemplateTemplateVersion.A TemplateVersion只是模板的下一个版本,所以TemplateVersion有一个Template(N:1关系)

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

public class TemplateVersion
{
    public int Id { get; set; }
    public Template Template { get;set; }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都清楚是一种有益的工作.

但是:我想获得关于Template级别的信息,这是当前版本的TemplateVersion,所以我的Template定义现在看起来像(TemplateVersion和以前一样)

public class Template 
{
    public int Id { get; set; }
    public TemplateVersion CurrentVersion { get; set;}
}
Run Code Online (Sandbox Code Playgroud)

所以我想有是N的情况下TemplateVersion,以点1的情况下Template却在同一时间Template指向1 TemplateVersion

在这里,魔术开始了:当我添加一个Template,TemplateVersion一切都运转良好.

Template ---- TemplateVersionPrevious.Template == Template
Run Code Online (Sandbox Code Playgroud)

但是,当我添加另一个TemplateVersion指向同一个Template(和更新TemplateCurrentVersion)的实例时,突然第一个实例将TemplateVersionTemplate字段置为无效.

Template ---- TemplateVersionPrevious.Template == null
         ---- TemplateVersionCurrent.Template == Template
Run Code Online (Sandbox Code Playgroud)

我相信这是因为实体框架认为我有一个经典的1:1关系,只有一个实例TemplateVersion可以Template与它有关系- 这是因为CurrentTemplate字段.

我如何告诉实体框架它不应该清除我的TemplateVersion关系?

附加信息:一旦我定义我的TemplateVersion实体如下

public class TemplateVersion
{
    public int Id { get; set; }
    [ForeignKey(nameof(TemplateId))]
    public Template Template { get;set; }
    public int TemplateId {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

它变得更有趣:之前的实例TemplateVersion刚被删除!

Template ---- TemplateVersionCurrent.Template == Template
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 6

EF默认约定不适用于2个实体之间的多个关系.并且数据注释不能很好地与一对一关系或单向关联(在一端没有导航属性的关系).

您需要使用流畅的API显式配置所需的关系.由于流利的API有不同的重载有/没有导航属性,并用它来纠正超载是很重要的,我们说你的模型是完全一样(正好我指的是导航和影响的关系,明确FK属性,其他属性都无关紧要):

public class Template 
{
    public int Id { get; set; }
    public TemplateVersion CurrentVersion { get; set; }
}

public class TemplateVersion
{
    public int Id { get; set; }
    public Template Template { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

所需两种关系的流畅配置如下:

modelBuilder.Entity<Template>()
    .HasMany<TemplateVersion>()
    .WithOne(e => e.Template)
    .IsRequired();

modelBuilder.Entity<Template>()
    .HasOne(e => e.CurrentVersion)
    .WithOne()
    .HasForeignKey<Template>("TemplateVersionId")
    .IsRequired(false);
Run Code Online (Sandbox Code Playgroud)

请注意,您已定义了循环关系,因此其中一个应该是可选的.我选择Template..TemplateVersionId对我来说是合乎逻辑的选择.

还要注意的是一个一对一的关系,校长和相关两端不能唯一地确定HasOne/ WithOne,所以你需要使用HasForeignKeyHasPrinciplaKey 泛型类型参数指定(相反,一个一对多的关系,有没有这样的问题,因为一方始终是委托人而另一方是依赖方.

有关详细信息,请参阅关系.