entity-framework - 多个表中的一对一映射

标签 entity-framework entity-framework-core relationship ef-core-2.0

我正在尝试解决一个谜题,但到目前为止还没有成功。

我有一篇文章(或博客文章)和评论实体,它们都有内容。为了支持内容的延迟加载(当我需要显示文章或评论列表时不需要加载内容),我决定将内容移动到单独的表并组织一对一映射。这是我的想法的一个例子:

public class Content {
    [Key]
    public int ID { get; set; }
    public string RawContent { get; set; }
    // a bunch of scalar properties, like content type and so on
}

public class BlogArticle {
    [Key]
    public int ID { get; set; }
    public int ContentID { get; set; }
    [ForeignKey(nameof(ContentID)]
    public virtual Content Text { get; set; }
    // other properties related to BlogArticle
}

public class Comment {
    [Key]
    public int ID { get; set; }
    public int ContentID { get; set; }
    [ForeignKey(nameof(ContentID)]
    public virtual Content Text { get; set; }
    // other properties related to comment
}
<...>

乍一看似乎没问题:我可以创建博客文章、评论和附加内容(显然,首先我插入内容)。更新也有效。但是,删除不起作用:当我删除博客文章或评论时,内容并没有被删除(但我想在删除博客文章或评论时删除它,而不是相反)。

据我了解,由于关系方向,我最大的问题是:在我的例子中,Content 实体是主体,BlogArticleComment 是依赖的目的。为了解决这个难题,我需要改变主/从关系。同样,根据我的理解,为了改变关系方向,我需要在 Content 实体中拥有外键,并使用流畅的 API 来描述谁是父级(主体)、谁是子级(依赖)。一对一的关系。由于许多表(可能还有其他具有 content 属性的实体)都指向 Content 表,因此看起来并不容易。我的理解正确吗?

我能想到的一个可能的解决方案是在 Content 表中创建多个外键并指向每个相关表:

public class Content {
    [Key]
    public int ID { get; set; }
    public string RawContent { get; set; }
    // foreign keys
    public int BlogArticleID { get; set; }
    public int CommentID { get; set; }
    public int WebWidgetID { get; set; }
    // other foreign keys if necessary
}

可能,外键必须可以为空(因为一次只使用单个外键)。然后使用Entity Framework Fluent API来描述关系方向并组织级联删除。对我来说它看起来很难看,但我没有其他想法。

我的问题:我提出的解决方案好/可靠吗?我还可以考虑其他选择吗?

提前致谢!

最佳答案

你的所有想法都是正确的。您提出的解决方案是传统关系设计的唯一方法。当然,缺点是需要多个互斥的可空 FK。

我看到的其他选项如下:

(1) 使用 EF inheritance对于持有内容的实体。例如

public abstract class EntityWithContent
{
    [Key]
    public int ID { get; set; }
    public virtual Content Text { get; set; }
}

public class BlogArticle : EntityWithContent
{
    // other specific properties
}

public class Comment : EntityWithContent
{
    // other specific properties
}

并使用共享 PK 关联或 FK 关联在 Content(从属)和 EntityWithContent(主体)之间配置一对一关系。

但是由于 EF Core 目前仅支持 TPH 策略(即所有派生实体共享一个且所有字段并集的同一张表),因此我不会推荐它。

(2) 制作内容 owned type .

这更接近意图,但不幸的是 EF Core 目前总是将拥有的实体数据与所有者数据一起加载(即使它们配置为由不同的数据库表提供),这违背了您最初的目标,所以我也不会建议这样做。

(3) 使用 table splitting功能。

如果主要目标很简单,就是支持受控(惰性/急切/显式)加载,并且 Content 始终必需,那么这可能是迄今为止最好的解决方案.

这需要更多的配置,但最后它会给您原始的表设计(每个实体一个表)以及所需的加载行为:

型号:

public abstract class Content
{
    [Key]
    public int ID { get; set; }
    public string RawContent { get; set; }
    // a bunch of scalar properties, like content type and so on
}

public class BlogArticle
{
    [Key]
    public int ID { get; set; }
    public virtual BlogArticleContent Text { get; set; }
    // other properties related to BlogArticle
}

public class BlogArticleContent : Content
{
}

public class Comment
{
    [Key]
    public int ID { get; set; }
    public virtual CommentContent Text { get; set; }
    // other properties related to comment
}

public class CommentContent : Content
{
}

请注意,这里的 Content 类不是 EF 继承层次结构的一部分,而是具有公共(public)属性的简单基类(并不强烈需要 abstract 修饰符)。实际的派生类可能会也可能不会定义自己的属性。

配置:

modelBuilder.Entity<BlogArticle>().ToTable("BlogArticles");
modelBuilder.Entity<BlogArticle>()
    .HasOne(e => e.Text)
    .WithOne()
    .HasForeignKey<BlogArticleContent>(e => e.ID);
modelBuilder.Entity<BlogArticleContent>().ToTable("BlogArticles");

modelBuilder.Entity<Comment>().ToTable("Comments");
modelBuilder.Entity<Comment>()
    .HasOne(e => e.Text)
    .WithOne()
    .HasForeignKey<CommentContent>(e => e.ID);
modelBuilder.Entity<CommentContent>().ToTable("Comments");

关于entity-framework - 多个表中的一对一映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49230065/

相关文章:

swift - 如何与核心数据建立多对多关系? swift ,xcode

php - Laravel "with"将变量大小写更改为蛇形大小写

c# - EF Core 包含多层次问题

c# - 最小起订量和设置数据库上下文

entity-framework - .NET 2.0 是否有类似 Entity Framework 的 ORM? (数据库优先!)

c# - 如何在 EF Core 中调用 ThenInclude 两次?

c# - 如何更新 Entity Framework Core 中修改的列?

php - Laravel通过pivot Table获取所有数据

c# - Entity Framework 从具有子实体的父实体中提取简单列表

c# - Entity Framework : Object Reference not set to instance of an object