三者区别
EF默认:TPH
TPH:基类和子类在一张表里,以Discriminator自动区别不同的类,Discriminator名称和值可在FlushApi中修改
modelBuilder.Entity<Dog>().Map<WhiteDog>(m => m.Requires("DogType").HasValue(1)).Map<BlackDog>(m => m.Requires("DogType").HasValue(2));
TPT:基类和子类在不同的表里,子类表中,没有基类的属性,以外键相连
TPC:基类没有单独的表,每个子类一张表,每个子类表中都含有基类的属性
如何实现:
TPH:默认,不自定义表名
TPT:ToTable(给哪个子类ToTable,哪个子类就单独表,其他的还在一张表里)
modelBuilder.Entity<Dog>().HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); //如果某个子类不写表名,则它会和基类表放在一起,其他写表名的子类依然会分开 modelBuilder.Entity<WhiteDog>().Map(m => { m.ToTable("WhiteDog"); }); modelBuilder.Entity<BlackDog>().Map(m => { m.ToTable("BlackDog"); }); modelBuilder.Entity<RedDog>().Map(m => { m.ToTable("RedDog"); });
TPC:ToTable + MapInheritedProperties(); + 基类为抽象类
TPC备注:
如果三张表里的Id一样的话,读取基类时会报主键相同的错误,如果是用Guid当主键就可以解决
如果不需要从总表读取统一读取,还不如把基类设置为抽象类,三个子类正常建就行了
TPC抽象类很重要,如果不是抽象类就变为TPT
如果一个子类调用了MapInheritedProperties,那么就要全部子类都要调用MapInheritedProperties,否则系统报错。
如果只调用MapInheritedProperties,不定义表名,则变为TPH
modelBuilder.Entity<Dog>().HasKey(e => e.Id);//TPC模式建议大家用Guid做为主键,如果是自增长主键,主键相同时,读取所有类的话,系统会报错 modelBuilder.Entity<WhiteDog>().Map(m => { m.MapInheritedProperties(); m.ToTable("WhiteDog"); }); modelBuilder.Entity<BlackDog>().Map(m => { m.MapInheritedProperties(); m.ToTable("BlackDog"); }); modelBuilder.Entity<RedDog>().Map(m => { m.MapInheritedProperties(); m.ToTable("RedDog"); });
如何使用:
无论哪种模式,EF的读取方式是一样的
读取所有子类:
var dogs = db.Dogs.Where(a => a.Id == 1).FirstOrDefault();
读取某个子类:
var dogs = db.Dogs.OfType<RedDog>().Where(a => a.Id == 1).FirstOrDefault();
读取多个子类:
var dogs = db.Dogs.Where(a => (a is BlackDog) || (a is RedDog)).ToList();
注意:如果OfType或is判断里的类型不是Dogs的本身或子类,则会报以下错误
DbOfTypeExpression requires an expression argument with a polymorphic result type that is compatible with the type argument.
每个类型一张表【TPT】
声明方式
public class Business
{
[Key]
public int BusinessId { get; protected set; }
public string Name { get; set; }
public string LicenseNumber { get; set; }
}
public class Retail : Business
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZIPCode { get; set; }
}
public class eCommerce : Business
{
public string URL { get; set; }
}public class BusinessesContext : DbContext
{
public DbSet<Business> Businesses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Business>()
.Property(b=>b.BusinessId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Business>().ToTable("Business", "halower");
modelBuilder.Entity<Retail>().ToTable("Retail", "halower");
modelBuilder.Entity<eCommerce>().ToTable("eCommerce", "halower");
}
}
怎么使用
private static void Main(string[] args)
{
using (var context = new BusinessesContext())
{
var retail = new Retail
{
Name = "Shop and Save",
LicenseNumber = "200C",
Address = "101 Main",
City = "Anytown",
State = "TX",
ZIPCode = "76106"
};
context.Businesses.Add(retail);
var web = new eCommerce
{
Name = "BuyNow.com",
LicenseNumber = "300AB",
URL = "www.buynow.com"
};
context.Businesses.Add(web);
context.SaveChanges();
}
using (var context = new BusinessesContext())
{
Console.WriteLine("\n--- All Businesses ---");
foreach (var b in context.Businesses)
{
Console.WriteLine("{0} (#{1})", b.Name, b.LicenseNumber);
}
Console.WriteLine("\n--- Retail Businesses ---");
//OfType<T>:根据指定类型筛选
foreach (var r in context.Businesses.OfType<Retail>())
{
Console.WriteLine("{0} (#{1})", r.Name, r.LicenseNumber);
Console.WriteLine("{0}", r.Address);
Console.WriteLine("{0}, {1} {2}", r.City, r.State, r.ZIPCode);
}
Console.WriteLine("\n--- eCommerce Businesses ---");
foreach (var e in context.Businesses.OfType<eCommerce>())
{
Console.WriteLine("{0} (#{1})", e.Name, e.LicenseNumber);
Console.WriteLine("Online address is: {0}", e.URL);
}
Console.ReadKey();
}
}
生成表结构

运行效果

每个继承层次一张表【TPH】
声明方式
public abstract class Employee
{
public int EmployeeId { get; protected set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class FullTimeEmployee : Employee
{
public decimal? Salary { get; set; }
}
public class HourlyEmployee : Employee
{
public decimal? Wage { get; set; }
}
public class EmployeeContext: DbContext
{
public DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Employee>()
.HasKey(e => e.EmployeeId)
.Property(e => e.EmployeeId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Employee>()
.Map<FullTimeEmployee>(m => m.Requires("EmployeeType").HasValue(1))
.Map<HourlyEmployee>(m => m.Requires("EmployeeType").HasValue(2));
}
怎么使用
private static void Main(string[] args)
{
using (var context = new EmployeeContext())
{
var fte = new FullTimeEmployee
{
FirstName = "Jane",
LastName = "Doe",
Salary = 71500M
};
context.Employees.Add(fte);
fte = new FullTimeEmployee
{
FirstName = "John",
LastName = "Smith",
Salary = 62500M
};
context.Employees.Add(fte);
var hourly = new HourlyEmployee
{
FirstName = "Tom",
LastName = "Jones",
Wage = 8.75M
};
context.Employees.Add(hourly);
context.SaveChanges();
}
using (var context = new EmployeeContext())
{
Console.WriteLine("--- All Employees ---");
foreach (var emp in context.Employees)
{
bool fullTime = !(emp is HourlyEmployee);
Console.WriteLine("{0} {1} ({2})", emp.FirstName, emp.LastName,
fullTime ? "Full Time" : "Hourly");
}
Console.WriteLine("--- Full Time ---");
foreach (var fte in context.Employees.OfType<FullTimeEmployee>())
{
Console.WriteLine("{0} {1}", fte.FirstName, fte.LastName);
}
Console.WriteLine("--- Hourly ---");
foreach (var hourly in context.Employees.OfType<HourlyEmployee>())
{
Console.WriteLine("{0} {1}", hourly.FirstName, hourly.LastName);
}
}
Console.ReadKey();
}
生成表结构

运行效果

每个子类一张表【TPC】
声明方式
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Employee>()
.HasKey(e => e.EmployeeId)
.Property(e => e.EmployeeId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<FullTimeEmployee>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("FullTimeEmployee");
});
modelBuilder.Entity<HourlyEmployee>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("HourlyEmployee");
});
}
生成表结构


浙公网安备 33010602011771号