实体映射与数据库迁移全解析
立即解锁
发布时间: 2025-08-23 01:41:57 阅读量: 1 订阅数: 7 

# 实体映射与数据库迁移全解析
## 1. 实体映射到数据库表的替代方法
### 1.1 按层次结构表(TPH)
在处理按层次结构表(TPH)时,EF Core 会保存正确版本的数据并设置鉴别器,以便识别实例的 TPH 类类型。当读取刚保存的 `SoldIt` 实体并使用 `Include` 加载 `Payment` 导航属性时,加载的 `Payment` 实例类型将根据写入数据库时使用的类型正确显示(如 `PaymentCash` 或 `PaymentCard`)。在查询 TPH 数据时,EF Core 的 `OfType<T>` 方法可用于过滤数据以查找特定类。例如,`context.Payments.OfType<PaymentCard>()` 仅返回使用卡支付的记录。还可以在 `Include` 中过滤 TPH 类,更多信息可参考 [此处](http://mng.bz/QmBj)。
### 1.2 按类型表(TPT)
#### 1.2.1 TPT 概述
EF Core 5 引入了按类型表(TPT)选项,允许从基类继承的每个实体类拥有自己的表,这与按层次结构表(TPH)方法相反。当继承层次结构中的每个类有大量不同信息时,TPT 是一个不错的解决方案;而当每个继承类有大量公共部分和少量特定于类的数据时,TPH 更合适。
#### 1.2.2 TPT 示例
以两种类型的容器为例:散货船上使用的运输容器和塑料容器(如瓶子、罐子和盒子)。两种容器都有整体高度、长度和深度,但其他方面不同。以下是三个实体类的代码:
```csharp
public abstract class Container
{
[Key]
public int ContainerId { get; set; }
public int HeightMm { get; set; }
public int WidthMm { get; set; }
public int DepthMm { get; set; }
}
public class ShippingContainer : Container
{
public int ThicknessMm { get; set; }
public string DoorType { get; set; }
public int StackingMax { get; set; }
public bool Refrigerated { get; set; }
}
public class PlasticContainer : Container
{
public int CapacityMl { get; set; }
public Shapes Shape { get; set; }
public string ColorARGB { get; set; }
}
```
接下来,需要配置应用程序的 `DbContext`,包括两部分:
1. 添加 `DbSet<Container>` 属性,用于访问所有容器。
2. 设置其他容器类型(`ShippingContainer` 和 `PlasticContainer`)映射到各自的表。
以下是配置代码:
```csharp
public class Chapter08DbContext : DbContext
{
public Chapter08DbContext(
DbContextOptions<Chapter08DbContext> options)
: base(options)
{ }
public DbSet<Container> Containers { get; set; }
protected override void OnModelCreating
(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ShippingContainer>()
.ToTable(nameof(ShippingContainer));
modelBuilder.Entity<PlasticContainer>()
.ToTable(nameof(PlasticContainer));
}
}
```
更新 `DbContext` 后会创建三个表:
- `Containers` 表,包含每个条目的公共数据。
- `ShippingContainer` 表,包含 `Container` 和 `ShippingContainer` 的属性。
- `PlasticContainer` 表,包含 `Container` 和 `PlasticContainer` 的属性。
添加 `ShippingContainer` 和 `PlasticContainer` 可使用 `context.Add` 方法。查询 `DbSet<Container> Containers` 时,会返回所有容器,并为每个返回的实体使用正确的类类型(`ShippingContainer` 或 `PlasticContainer`)。加载 TPT 类的一种类型有以下三种方法,效率依次提高:
| 方法 | 描述 |
| ---- | ---- |
| 全读取查询 `context.Containers.ToList()` | 读取所有 TPT 类型,列表中的每个条目将是返回类型的正确类型。仅在需要列出所有容器的摘要时有用。 |
| `OfType` 查询 `context.Containers.OfType<ShippingContainer>().ToList()` | 仅读取 `ShippingContainer` 类型的条目。 |
| `Set` 查询 `context.Set<ShippingContainer>().ToList()` | 仅返回 `ShippingContainer` 类型(与 `OfType` 查询相同),但 SQL 效率略高于 `OfType` 查询。 |
### 1.3 表拆分
表拆分允许将多个实体映射到同一个表。当一个实体需要存储大量数据,但正常查询只需要几列时,此功能很有用。表拆分就像在实体类中构建 `Select` 查询,由于只加载整个实体数据的一部分,查询会更快,通过将表拆分为两个或多个类,更新也会更快。
以下是一个示例,有两个实体类 `BookSummary` 和 `BookDetail`,都映射到名为 `Books` 的数据库表:
```csharp
public class BookSummary
{
public int BookSummaryId { get; set; }
public string Title { get; set; }
public string AuthorString { get; set; }
public BookDetail Details { get; set; }
}
CREATE TABLE [Books] (
[BookSummaryId] int NOT NULL IDENTITY,
[Title] nvarchar(max) NULL,
[AuthorsString] nvarchar(max) NULL,
[Description] nvarchar(max) NULL,
[Price] decimal(18, 2) NOT NULL,
CONSTRAINT [PK Book] PRIMARY KEY ([BookId])
);
public class BookDetail
{
public int BookDetailId { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
}
```
配置代码如下:
```csharp
public class SplitOwnDbContext : DbContext
{
protecte
```
0
0
复制全文
相关推荐










