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,但手动数据操作操作可能会把事情搞砸(例如 Park
和 Restaurant
可以引用相同的 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>
,则不需要 Restaurants
或 Parks
DbSet<T>
。或者,如果您为派生类型包含 DbSet<T>
,则 Spots
是可选的。
我鼓励您以两种方式为您的实体建模,以了解 EF 如何为 DB 建模并选择您喜欢的方式。
https://docs.microsoft.com/en-us/ef/core/modeling/inheritance
我有一个 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,但手动数据操作操作可能会把事情搞砸(例如 Park
和 Restaurant
可以引用相同的 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>
,则不需要 Restaurants
或 Parks
DbSet<T>
。或者,如果您为派生类型包含 DbSet<T>
,则 Spots
是可选的。
我鼓励您以两种方式为您的实体建模,以了解 EF 如何为 DB 建模并选择您喜欢的方式。
https://docs.microsoft.com/en-us/ef/core/modeling/inheritance