EntityFramework进阶——继承
通過類型繼承,我們可以更彈性地處理數(shù)據(jù),有3中相關(guān)的技巧,即TPH,TPT,TPC。
?
Table Per Hierarchy(TPH)
當(dāng)單個數(shù)據(jù)表存儲不同數(shù)據(jù)類型時,在數(shù)據(jù)模型的設(shè)計上,可以使用Table Per Hierarchy(TPH,每個層次結(jié)構(gòu)一張表)設(shè)計分割成數(shù)個不同的類型。在通過繼承來建立彼此的關(guān)系。
新建一個空的控制臺項目:TPHDemo。添加如下幾個實體類:
public class Product{public int Id { get; set; }public string Name { get; set; }public int Price { get; set; }}public class Magazine:Product{public int Year { get; set; }public int Month { get; set; }public string ISSN { get; set; }public int MPages { get; set; }}public class Book:Product{public string Title { get; set; }public string ISBN { get; set; }public string Author { get; set; }public int Pages { get; set; }}上下文類代碼如下圖所示:
public class TPHModel : DbContext{public TPHModel(): base("name=TPHModel"){}public virtual DbSet<Product> Product { get; set; }}運行項目生成數(shù)據(jù)庫中的表結(jié)構(gòu)如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
這個數(shù)據(jù)表存儲各種類型的商品,我們可以將其中的數(shù)據(jù)字段分割成3部分,以針對特定的數(shù)據(jù)進(jìn)行存儲。分別是一般性商品的共同數(shù)據(jù)、圖書、雜志。結(jié)構(gòu)如下圖所示:
| ? | 字段名 | 說明 | 數(shù)據(jù)類型 |
| 一般性商品的共同數(shù)據(jù) | Id | 商品識別編號 | int |
| Name | 商品名稱 | string | |
| Price | 價格 | int | |
| 圖書 | Title | 書名 | string |
| ISBN | 圖書ISBN編碼 | string | |
| Author | 作者 | string | |
| Pages | 頁數(shù) | int | |
| 雜志 | Years | 雜志年份 | int |
| Month | 雜志月份 | int | |
| ISSN | 雜志ISSN編碼 | string | |
| MPages | 雜志頁數(shù) | int |
現(xiàn)在向Main函數(shù)中加入代碼,目的是向數(shù)據(jù)庫中插入數(shù)據(jù):
static void Main(string[] args){using (TPHModel db = new TPHModel()){Product book = new Book{Name = "圖書",Price = 12,Title = "EF進(jìn)階",ISBN = "001",Author = "admin",Pages = 1000};db.Product.Add(book);Product magazine = new Magazine{Name = "雜志",Price = 10,Year = 2019,Month = 10,ISSN = "0001",MPages = 500};db.Product.Add(magazine);db.SaveChanges();}}?向數(shù)據(jù)庫中插入的數(shù)據(jù)如下圖所示:
? ? ? ? ? ? ? ??
向數(shù)據(jù)庫中取出插入的數(shù)據(jù),可編輯如下代碼:
static void Main(string[] args) {using (TPHModel db = new TPHModel()){var bs = db.Product.OfType<Book>().Where(p => p.Id == 1);//篩選出Book類型if (bs.Any()){Book b = bs.Single();Console.WriteLine("\n{0}--{1}\n\n 書名:{2}\n 價格:{3}\n ISBN:{4}\n 頁數(shù):{5}\n 作者:{6}",b.Id,b.Name,b.Title,b.Price,b.ISBN,b.Pages,b.Author);Console.ReadKey();}else{Console.WriteLine("無此書編號");}} }運行效果如下圖所示:
? ? ? ? ? ? ? ? ? ? ??
?
?Table Per Type(TPT)
Table per Type(TPT,每種類型一張表)通過類型繼承建立數(shù)據(jù)實體對應(yīng)到關(guān)聯(lián)數(shù)據(jù)表的外鍵,與TPH不同的地方在于,每一個數(shù)據(jù)類型對應(yīng)到獨立的數(shù)據(jù)表,數(shù)據(jù)表彼此形成關(guān)聯(lián)的外鍵就形成類型彼此間的繼承關(guān)系。
新建一個空的控制臺應(yīng)用程序:TPTDemo,添加如下幾個實體類:
[Table("Product")]public class Product{public int Id { get; set; }public string Name { get; set; }public int Price { get; set; }}[Table("Book")]public class Book:Product{public string Title { get; set; }public string ISBN { get; set; }public string Author { get; set; }public int Pages { get; set; }}[Table("Magazine")]public class Magazine:Product{public int Year { get; set; }public int Month { get; set; }public string ISSN { get; set; }public int MPages { get; set; }}上下文類代碼如下圖所示:
public class TPTModel : DbContext{public TPTModel(): base("name=TPTModel"){}public virtual DbSet<Product> Product { get; set; }}運行項目后,數(shù)據(jù)庫中新建的表表結(jié)構(gòu)如如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
修改Main函數(shù)中的代碼,目標(biāo)是插入一些數(shù)據(jù):?
static void Main(string[] args){using (TPTModel db = new TPTModel()){Product book = new Book{Name = "圖書",Title = "EF進(jìn)階",ISBN = "001",Author = "admin",Pages = 500,};db.Product.Add(book);Product magezine = new Magazine{Name = "雜志",Year = 2019,Month = 10,ISSN = "00001",MPages = 1000,};db.Product.Add(magezine);db.SaveChanges();Console.WriteLine("insert successd");}}數(shù)據(jù)插入數(shù)據(jù)表后,如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
修改Main函數(shù)中代碼,目標(biāo)是查詢出表中的數(shù)據(jù),如下圖所示:
static void Main(string[] args) {using (TPTModel db = new TPTModel()){var Products = db.Product;Console.WriteLine("\n圖書列表:\n");foreach (var book in Products.OfType<Book>()){Console.WriteLine("{0} 頁數(shù):{1} ISBN:{2} 作者:{3}",book.Title,book.Pages,book.ISBN,book.Author);}Console.WriteLine("\n雜志列表:\n");foreach (var magazine in Products.OfType<Magazine>()){Console.WriteLine("{0} 頁數(shù):{1} ISSN:{2} 年份:{3} 月份:{4}",magazine.Name,magazine.MPages,magazine.ISSN,magazine.Year,magazine.Month);}Console.Read(); } }運行結(jié)果如下圖所示:
? ? ? ? ? ? ? ? ? ??
Table Per Concrete Class(TPC)?
TPH通過幾個類表示單個數(shù)據(jù)表,并且由派生類屬性對應(yīng)特定的字段。如果想要派生類同時擁有基類的共同屬性,可以嘗試TPC策略。
新建空的控制臺應(yīng)用程序 :TPCDemo,新增實體類如下圖所示:
public class Product{public int Id { get; set; }public string Name { get; set; }public int Price { get; set; }}public class Book:Product{public string Title { get; set; }public string ISBN { get; set; }public string Author { get; set; }public int Pages { get; set; }}public class Magazine:Product{public int Year { get; set; }public int Month { get; set; }public string ISSN { get; set; }public string MPages { get; set; }}上下文類代碼如下圖所示:
public class TPCModel : DbContext {public TPCModel(): base("name=TPCModel"){}protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Entity<Product>().Property(c => c.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);modelBuilder.Entity<Book>().Map(m => {m.MapInheritedProperties();m.ToTable("Book");});modelBuilder.Entity<Magazine>().Map(m => {m.MapInheritedProperties();m.ToTable("Magazine");});}public virtual DbSet<Product> Product { get; set; } }運行項目,在數(shù)據(jù)庫中建的表結(jié)構(gòu)如下圖所示:
? ? ? ? ? ? ? ? ???
?
修改Main函數(shù)中的方法,目標(biāo)為向數(shù)據(jù)表中插入一些數(shù)據(jù),代碼如下圖所示:
static void Main(string[] args){using (TPCModel db = new TPCModel()){Book book = new Book{Id = 1,Name = "圖書",Price = 100,Title = "EF進(jìn)階",ISBN = "001",Author = "admin",Pages = 1000,};db.Product.Add(book);Magazine magazine = new Magazine{Id = 2,Name = "雜志",Price = 500,Year = 2019,Month = 10,ISSN = "0001",MPages = "500",};db.Product.Add(magazine);db.SaveChanges();Console.WriteLine("OK");}}運行程序后數(shù)據(jù)表的中結(jié)果如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ???
采用TPC策略與TPH有類似性,但是在每一種類型的數(shù)據(jù)添加過程中都必須指定Id和Name等共享字段的值,而且Product、Book、Magazine類對應(yīng)的數(shù)據(jù)表中,Id字段不能存在重復(fù)的值。?
讀取數(shù)據(jù)表中的字段代碼如下圖所示:
static void Main(string[] args) {using (TPCModel db = new TPCModel()){var books = db.Product.OfType<Book>();foreach (var book in books){Console.WriteLine("Name:{0},Price:{1}, Title:{2} ,ISBN:{3},Author:{4}, Pages:{5}",book.Name,book.Price,book.Title,book.ISBN,book.Author,book.Pages);}Console.ReadKey();} }?運行結(jié)果如下圖所示:
? ? ? ? ? ? ??
復(fù)雜類型
當(dāng)一個實體類不具備Id之類的鍵值標(biāo)識屬性時,在EF定義上是一種復(fù)雜類型。如果我們想要單個數(shù)據(jù)表的字段用不同類型的屬性完成對應(yīng),那么復(fù)雜類型就非常適合這種情況。
| 共同商品的數(shù)據(jù) | Id | 商品識別編號 | int |
| Name | 商品名稱 | string | |
| Price | 價格 | int | |
| 圖書類型的數(shù)據(jù) | Title | 書名 | string? |
| ISBN | ISBN編號 | string | |
| Author | 作者 | string | |
| Pages | 頁數(shù) | int |
?
新建空的控制臺應(yīng)用程序:ComplexTypeDemo,新增實體類如下圖所示:
public class Product{public int Id { get; set; }public string Name { get; set; }public int Price { get; set; }public Book Book { get; set; }}public class Book{public string Title { get; set; }public string ISBN { get; set; }public string Author { get; set; }public int Pages { get; set; }}?上下文類中的代碼如下圖所示:
public class ComplexTypeModel : DbContext{public ComplexTypeModel(): base("name=ComplexTypeModel"){}public virtual DbSet<Product> Product { get; set; }}運行程序后,建立的數(shù)據(jù)表如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
生成的列名帶有Book前綴這是默認(rèn)的操作,如果要將其對應(yīng)到指定的數(shù)據(jù)字段,比如沒有Book前綴,就需要數(shù)據(jù)注解進(jìn)行注釋,如下圖所示:
public class Book{[Column("Title")]public string Title { get; set; }[Column("ISBN")]public string ISBN { get; set; }[Column("Author")]public string Author { get; set; }[Column("Pages")]public int Pages { get; set; }}修改main函數(shù)代碼,?目標(biāo)是往表里插入數(shù)據(jù),代碼如下圖所示:
static void Main(string[] args){using (ComplexTypeModel db = new ComplexTypeModel()) {var book = new Book{Title = "新的圖書",ISBN = "0001",Author = "admin",Pages = 100,};var product = new Product{Name = "圖書",Price = 1000,Book = book,};db.Product.Add(product);db.SaveChanges();Console.WriteLine("OK");}}運行后插入數(shù)據(jù)后,表中內(nèi)容如下圖所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
修改main函數(shù)中的代碼,執(zhí)行查詢操作:
static void Main(string[] args) {using (ComplexTypeModel db = new ComplexTypeModel()) {foreach (Product product in db.Product){Console.WriteLine("\n\n 商品名稱是:{0},商品價格是:{1}",product.Name,product.Price);Console.WriteLine("\n書名是:{0} ISBN編號是:{1} 作者是:{2} 頁數(shù)是:{3}", product.Book.Title, product.Book.ISBN, product.Book.Author, product.Book.Pages);}Console.ReadKey();} }運行效果如下圖所示:
? ? ? ? ? ? ? ???
?
?
總結(jié)
以上是生活随笔為你收集整理的EntityFramework进阶——继承的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis的zset使用(java)——
- 下一篇: NLM和BM3D