C# EF 核心模型独立 FK

C# EF Core Models independent FK

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

是否可以在 table 位置创建一个独立于类别的列(FK)? 我的意思是,当我创建一个类别为 Resteraunt 的新地点时,下一个地点是类别公园。 如果我现在 select 一个地点,我从相应的地点类别中获得正确的数据

如果可能,我如何在 C# EF 核心模型中编写它?

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

提前致谢

数据库设计示例:

不,你不能有一个独立于它引用的 table 的 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
}

然后您以两种方式之一映射实体 - 映射到单个 table (TPH),它将使用 discriminator 列到 type 数据库中的每条记录(将被视为您的 category),派生类型的每个 属性 也将包括在内,但仅针对特定类型的记录进行填充(即 Park 属性将 null 当DB 中的记录表示 Restaurant,反之亦然)。使用此方法的查询性能更快,但所有特定于类型的列都必须可以为空,并且此实现违反了 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 中,继承层次结构中的每个类型都映射到它自己的 table,其中包含它们的特定属性。派生类型的 tables 使用共享主键来引用它们对应的 Spot 记录。查询性能可能会变慢,虽然它不违反 3NF,但手动数据操作操作可能会把事情搞砸(例如 ParkRestaurant 可以引用相同的 Spot 记录).

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

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<T>()

Spots 中获取特定类型的 Spot
var parks = dbContext.Spots.OfType<Park>();

因此,如果包含 Spot DbSet<T>,则不需要 RestaurantsParks DbSet<T>。或者,如果您为派生类型包含 DbSet<T>,则 Spots 是可选的。

我鼓励您以两种方式为您的实体建模,以了解 EF 如何为 DB 建模并选择您喜欢的方式。

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