前言:
继承影射其实也可以作为实体关系的一种,
但使用的地方明显比较少一些.
在Hibernate中,
继承映射主要有两种方式
1.单表继承映射
2.多表继承映射
当然比较好用的是单表继承映射,(只需要设置一个鉴别器属性即可),总体比较简单
EFCore的继承映射也分为这两种情况,分别是单表和多表
但不同的是
按照约定,EF 不会自动扫描基类型或派生类型;这意味着,如果要映射层次结构中的 CLR 类型,就必须在模型上显式指定该类型。 例如,仅指定层次结构的基类型不会导致 EF Core 隐式包含其所有子类型。(通俗一点说就是把所有的父类,子类都放到一个DbSet中放到DbContext里)
一.单表继承映射
以动物之间的关系为例
//基类
class Animal
{
public int id { get; set; }
public string name { get; set; }
}
//子类:鱼
class Fish:Animal
{
public int flags;
}
//子类:狗
class dog : Animal
{
public int feet { get; set; }
public string owner { get; set; }
}
//子类:熊
class Bear:Animal
{
public string woodName { get; set; }
public double wegiht { get; set; }
}
数据库上下文:
class ExtendDbContext:DbContext
{
//将基类和子类都放在DbContext中
public DbSet<Animal> animals { get; set; }
public DbSet<dog> dogs { get; set; }
public DbSet<Fish> fishes { get; set; }
public DbSet<Bear> bears { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var Connection = "server=XX;Database=XXX;uid=XXX;pwd=XXX";
optionsBuilder.UseSqlServer(Connection);
}
}
输入
add-migration initialcreate -c ExtendDbContext
update-database -Context ExtendDbContext
成功的话进入迁移文件的建表代码
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "animals",
columns: table => new
{
id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
name = table.Column<string>(type: "nvarchar(max)", nullable: true),
//自动创建了鉴别器字段
Discriminator = table.Column<string>(type: "nvarchar(max)", nullable: false),
//下面都是子类的特有属性
woodName = table.Column<string>(type: "nvarchar(max)", nullable: true),
wegiht = table.Column<double>(type: "float", nullable: true),
feet = table.Column<int>(type: "int", nullable: true),
owner = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_animals", x => x.id);
});
}
默认EFCore是单表继承映射,它会默认生成一个鉴别器字段在表中同时也是一个影子属性
表结构:
插入两条数据试试看
static void Main(string[] args)
{
//繼承映射測試Demo
ExtendDbContext context = new ExtendDbContext();
dog d1 = new dog();
d1.name = "旺財";
d1.owner = "jotaro";
d1.feet = 4;
Bear xionger = new Bear();
xionger.name = "熊二";
xionger.woodName = "西伯利亞";
xionger.wegiht = 400.00;
context.dogs.Add(d1);
context.bears.Add(xionger);
context.SaveChanges();
}
(单表继承映射与普通映射的区别是单表继承映射把一张表映射并维护成多个对象)
(PS.鉴别器字段也可以在FluentAPI中指定,虽然没有必要)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property("Discriminator")
.HasMaxLength(200);
}
二.多表继承映射
//多表继承的基类
class Computer
{
public String id { get; set; }
public String CPU { get; set; }
public int RAM { get; set; }
}
//多表继承的子类
class laptop:Computer
{
public String LAPTOP_Screen { get; set; }
public String ModeID { get; set; }
}
class PC:Computer
{
public String PC_Screen { get; set; }
public String PC_box { get; set; }
}
数据库上下文:
class ExtendDbContextSec : DbContext
{
public DbSet<Computer> computers { get; set; }
public DbSet<PC> PCs { get; set; }
public DbSet<laptop> laptops { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var Connection = "server=XX;Database=XXX;uid=XX;pwd=XXXX";
optionsBuilder.UseSqlServer(Connection);
}
//多表繼承映射只需要在FluentAPI里为每一种实体指定一张数据表即可
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Computer>().ToTable("t_computer");
modelBuilder.Entity<laptop>().ToTable("t_laptop");
modelBuilder.Entity<PC>().ToTable("t_pcs");
}
}
同样查看一下建表语句:
protected override void Up(MigrationBuilder migrationBuilder)
{
//创建基类表
migrationBuilder.CreateTable(
name: "t_computer",
columns: table => new
{
id = table.Column<string>(type: "nvarchar(450)", nullable: false),
CPU = table.Column<string>(type: "nvarchar(max)", nullable: true),
RAM = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_t_computer", x => x.id);
});
//创建子类表
migrationBuilder.CreateTable(
name: "t_laptop",
columns: table => new
{
id = table.Column<string>(type: "nvarchar(450)", nullable: false),
LAPTOP_Screen = table.Column<string>(type: "nvarchar(max)", nullable: true),
ModeID = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
//自动添加主键,同时也作为外键参考t_computer的主键
constraints: table =>
{
table.PrimaryKey("PK_t_laptop", x => x.id);
table.ForeignKey(
name: "FK_t_laptop_t_computer_id",
column: x => x.id,
principalTable: "t_computer",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
});
//创建子类表
migrationBuilder.CreateTable(
name: "t_pcs",
columns: table => new
{
id = table.Column<string>(type: "nvarchar(450)", nullable: false),
PC_Screen = table.Column<string>(type: "nvarchar(max)", nullable: true),
PC_box = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
//自动添加主键,同时也作为外键参考t_computer的主键
constraints: table =>
{
table.PrimaryKey("PK_t_pcs", x => x.id);
table.ForeignKey(
name: "FK_t_pcs_t_computer_id",
column: x => x.id,
principalTable: "t_computer",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
});
}
数据库表结构:
测试:
static void Main(string[] args)
{
ExtendDbContextSec contextSec = new ExtendDbContextSec();
laptop rog = new laptop();
rog.CPU = "i7-11800h";
rog.RAM = 32;
rog.LAPTOP_Screen = "300hz";
rog.ModeID = "XHX";
PC taishi = new PC();
taishi.CPU = "i9-12900k";
taishi.RAM = 16;
taishi.PC_box = "alien";
taishi.PC_Screen = "AOC XXXXX";
contextSec.PCs.Add(taishi);
contextSec.laptops.Add(rog);
contextSec.SaveChanges();
}