EF6 秘籍 2th:实体数据建模基础 (十一)建模TPT(Table per Type)继承

问题描述:

    假设有一些表用于保存公共表的额外信息,现在想使用TPT继承对其建模。

解决方案:

    假定现在有2个表关联到一个公共表,如下图所示:

wKioL1aDyvagCNyfAAGHZ3O8ohg213.png

    Business表和Retail表及eCommerce表间都是一个1对零个或1个的关系,其中Business表是1端。关键的特点是Retail表和eCommerce表扩展了Business表中business的信息。

    Business表包含一些任何business都有的公共属性,Retail表和eCommerce表都同它紧密相连。为了建模一个TPT继承,也就是说Retail实体类型和eCommerce实体类型都继承于Business基实体类型,需要实现以下步骤:

    1、生成一个派生自DbContext类的类,需要引入System.Data.Entity名称空间,添加默认构造函数,并调用父类的构造函数base("name=connectionStringName")。connectionStringName是EF框架的连接字符串名称,在配置文件中可以找到,没有的话需要手动添加或使用EDM向导的代码优先方式创建。并重写父类的OnModelCreating方法。

    2、生成一个Business POCO 实体类型。

    [Table("Business",Schema ="Chapter2")]
    public class Business
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int BusinessId { get; set; }
        public string Name { get; set; }
        public string LicenseNumber { get; set; }
    }

    3、生成一个eCommerce POCO 实体类型和Retail POCO 实体类型,它们都继承于Business POCO实体类型。

    [Table("eCommerce",Schema ="Chapter2")]
    public class eCommerce:Business
    {
        public string URL { get; set; }
    }
    [Table("Retail",Schema ="Chapter2")]
    public class Retail : Business
    {
        public string Address { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string ZIPCode { get; set; }
    }

    4、在DbContext子类中添加一个DbSet<Business>自动属性。

原理:

    Retail表和eCommerce表是同Business表的1:0..1关系的0..1端。这意味着一个business实体可以没有任何额外的信息,也可以有额外的Retail信息或eCommerce信息。在OOP术语中,描述为一个基类型Business和2个派生类型Retail和eCommerce。

    因为这是一个1:0..1的关系,所以在Retail表和eCommerce表中不存在这样的记录,它们在Business表中不存在相关的记录。在面向对象的术语中描述为,派生类的实例包含有基类的属性。派生类扩展基类属性的概念是继承的关键特性之一。在TPT继承中,每一个派生类都表示为一个单独的表。

            using (var context = new EF6Recipes8Context())
            {
                var business = new Business { Name = "Corner Dry Cleaning", LicenseNumber = "100x1" };
                context.Businesses.Add(business);
                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 EF6Recipes8Context())
            {
                Console.WriteLine("\n--- All Business ---");
                foreach (var b in context.Businesses)
                {
                    Console.WriteLine("{0} (#{1})", b.Name, b.LicenseNumber);
                }
                Console.WriteLine("\n---Retail Business ---");
                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 Business ---");
                foreach (var e in context.Businesses.OfType<eCommerce>())
                {
                    Console.WriteLine("{0} (#{1})", e.Name, e.LicenseNumber);
                    Console.WriteLine("Online address is: {0}", e.URL);
                }
            }

    上面的代码生成和实例化Business实体类型和2个派生类型,并使用context中的Business实体集合的Add()方法将其添加到context中。

    在查询部分,为了访问所有的business实例,我们迭代整个business实体集合;为了获取派生类型,我们调用OfType方法过滤Business实体集合。

wKiom1aMva7DnokjAAAa0Q6nkt8216.png

    TPT是EF支持的3种继承模式中的一个。另外2个是TPH(Table per Hierarchy)和TPCT(Table per Concrete Type)。

    TPT继承提供了很大的数据库灵活性,我们能够容易的添加表作为一个派生类型,并按照它们自己的方式添加到模型中。然而,每一个派生类型涉及额外的连接,这将导致性能下降。在实际的应用中,使用TPT时,我们已经看到显著的性能问题当一些派生类被建模时。

    而TPH存储整个继承在单个表,它消除了TPT的连接,因此提供更好的性能,但更低的灵活性。

    TPCT被EF运行时支持,而不是设计时。

你可能感兴趣的:(entityframework,TPT)