Billpeng Space

技术源自生活
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Entity Framework、 代码优先,TPH、TPT、TPC与继承类

Posted on 2020-04-13 17:23  billpeng  阅读(445)  评论(0编辑  收藏  举报
 三者区别
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");
                    });
            }
复制代码

生成表结构