C# EF Core 模型独立 FK

Posted

技术标签:

【中文标题】C# EF Core 模型独立 FK【英文标题】:C# EF Core Models independent FK 【发布时间】:2021-07-24 18:41:46 【问题描述】:

我有一张桌子可以坐。这个点可以有不同的类别。例如:餐厅、酒店、公园。 每个单独的类别都有额外的和不同的细节。 我现在的问题:

是否可以在点表中创建一个独立于类别的列(FK)? 我的意思是当我创建一个类别为餐厅的新地点,而下一个类别是公园类别时。 如果我现在选择一个点,我会从相应的点类别中获得正确的数据

如果可能的话,我如何在 C# EF Core 模型中编写它?

或者这是不可能的,我必须采取其他方式?

提前致谢

以数据库设计为例:

【问题讨论】:

【参考方案1】:

不,你不能有一个独立于它所引用的表的 FK 列(category 的表现形式)。您正在寻找的是继承。 EF Core 5 当前支持两种类型的继承 - Table Per Hierarcy (TPH) 和 Table Per Type。两者都可以满足您的目的。

首先,您在继承层次结构中实现实体 Classe,以映射到数据库,派生类表示 Spot 的“类别”:

public abstract class Spot

    public Guid Id  get; set; 
    // common spot properties here 
    // (i.e. props shared by different types of spots like address)


public class Restaurant : Spot

    // restaurant specific properties here


public class Park : Spot

    // park specific properties here

然后您以两种方式之一将实体映射到单个表 (TPH),该表将使用 discriminator 列到 type 数据库中的每条记录(将被视为您的 category)和每个派生类型的属性也将包括在内,但仅填充特定类型的记录(即,当 DB 中的记录表示 Restaurant 时,Park 属性将为 null,反之亦然)。使用此方法可以提高查询性能,但所有特定类型的列都必须可以为空,并且此实现违反了3NF。

TPH 是默认的继承实现,但您可以配置它如何像处理任何其他属性(名称、数据类型)一样处理鉴别器,并为每个派生类型指定要使用的值:

modelBuilder.Entity<Spot>()
    .HasDescriminator("Category") // name it what you want
    .HasValue<Restaurant>("R") // value for restaurants
    .HasValue<Park>("P") // value for parks
    ;

在 TPT 中,继承层次结构中的每个类型都映射到包含其特定属性的自己的表。派生类型的表使用共享主键来引用它们对应的Spot 记录。查询性能可能会变慢,虽然它不违反 3NF,但手动数据操作操作可能会搞砸事情(例如 ParkRestaurant 可以引用相同的 Spot 记录)。

对于此配置,只需将实体层次结构中的每个类型映射到其自己的表:

modelBulider.Entity<Restaurant>().ToTable("Restaurant");
modelBuilder.Entity<Park>().ToTable("Park");

对于这两种实现,您都可以正常实现DbSet属性:

public DbSet<Spot> Spots  get; set; 
public DbSet<Restaurant> Restaurants  get; set; 
public DbSet<Park> Parks  get; set; 

您可以使用.OfType&lt;T&gt;()Spots获取特定类型的Spots

var parks = dbContext.Spots.OfType<Park>();

因此,如果包含Spots DbSet&lt;T&gt;,则不需要RestaurantsParks DbSet&lt;T&gt;s。或者,如果您为派生类型包含 DbSet&lt;T&gt;s,则 Spots 是可选的。

我鼓励您以两种方式对实体进行建模,以了解 EF 如何对数据库进行建模并选择您喜欢的方式。

https://docs.microsoft.com/en-us/ef/core/modeling/inheritance

【讨论】:

非常感谢我采用了 TPT 方法,效果如我所愿

以上是关于C# EF Core 模型独立 FK的主要内容,如果未能解决你的问题,请参考以下文章

如何在不将实例模型添加到数据库的情况下向实体模型添加FK约束?

将 LinqKit PredicateBuilder 用于相关模型(EF Core)

4.EF Core 数据库映射模型基本配置

5.EF Core 数据库映射模型隐藏属性配置

由于产生时间成本,禁用 EF Core 3.1 的模型验证

(17)ASP.NET Core EF基于数据模型创建数据库