《Entity Framework 6 Recipes》中文翻譯系列 (29) ------ 第五章 加載實體和導航屬性之過濾預先加載的實體集合和修改外鍵關聯

翻譯的初衷以及爲何選擇《Entity Framework 6 Recipes》來學習,請看本系列開篇html

5-13  過濾預先加載的實體集合

問題數據庫

  你想過濾預先加載的實體集合,另外,你想使用Code-First來管理數據訪問框架

解決方案ide

  實體框架不支持直接使用Include()時過濾關聯實體集合,但咱們能夠經過建立一個匿名類型來完成一樣的事情,匿名類型包含實體和要過濾的關聯實體集合。學習

  假設你有如圖5-28所示的概念模型ui

圖5-28 一個包含movies(電影)和它的categories(目錄)的模型spa

 在Visual Studio中添加一個名爲Recipe13的控制檯應用,並確保引用了實體框架6的庫,NuGet能夠很好的完成這個任務。在Reference目錄上右鍵,並選擇 Manage NeGet Packages(管理NeGet包),在Online頁,定位並安裝實體框架6的包。這樣操做後,NeGet將下載,安裝和配置實體框架6的庫到你的項目中。翻譯

  接下來咱們建立兩個實體對象:Moviet和Category,複製代碼清單5-33中的屬性到這三個類中。code

代碼清單5-33. 實體類htm

 public class Category
    {
        public Category()
        {
            Movies = new HashSet<Movie>();
        }

        public int CategoryId { get; set; }
        public string Name { get; set; }
        public string ReleaseType { get; set; }

        public virtual ICollection<Movie> Movies { get; set; }
    }

 public class Movie
    {
        public int MovieId { get; set; }
        public string Name { get; set; }
        public string Rating { get; set; }
        public int CategoryId { get; set; }

        public virtual Category Category { get; set; }
    }

接下來,建立一個名爲Recipe13Context的類,並將代碼清單5-34中的代碼添加到其中,並確保其派生到DbContext類。

代碼清單5-34. 上下文

 1  public class Recipe13Context : DbContext
 2     {
 3         public Recipe13Context()
 4             : base("Recipe13ConnectionString")
 5         {
 6             //禁用實體框架的模型兼容
 7             Database.SetInitializer<Recipe13Context>(null);
 8         }
 9 
10         public DbSet<Category> Categories { get; set; }
11         public DbSet<Movie> Movies { get; set; }
12 
13         protected override void OnModelCreating(DbModelBuilder modelBuilder)
14         {
15             modelBuilder.Entity<Category>().ToTable("Chapter5.Category");
16             modelBuilder.Entity<Movie>().ToTable("Chapter5.Movie");
17         }
18     }

接下來添加App.Config文件到項目中,並使用代碼清單5-35中的代碼添加到文件的ConnectionStrings小節下。

代碼清單5-35. 鏈接字符串

<connectionStrings>
<add name="Recipe13ConnectionString"
connectionString="Data Source=.;
Initial Catalog=EFRecipes;
Integrated Security=True;
MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>

   爲了過濾categoryes和與之關聯的movies,請按代碼清單5-36的方式進行。

 代碼清單5-36.過濾預先加載的實體集合

 1  using (var context = new Recipe13Context())
 2             {
 3                 var cat1 = new Category {Name = "Science Fiction", ReleaseType = "DVD"};
 4                 var cat2 = new Category {Name = "Thriller", ReleaseType = "Blu-Ray"};
 5                 var movie1 = new Movie {Name = "Return to the Moon", Category = cat1, Rating = "PG-13"};
 6                 var movie2 = new Movie {Name = "Street Smarts", Category = cat2, Rating = "PG-13"};
 7                 var movie3 = new Movie {Name = "Alien Revenge", Category = cat1, Rating = "R"};
 8                 var movie4 = new Movie {Name = "Saturday Nights", Category = cat1, Rating = "PG-13"};
 9                 context.Categories.Add(cat1);
10                 context.Categories.Add(cat2);
11                 context.Movies.Add(movie1);
12                 context.Movies.Add(movie2);
13                 context.Movies.Add(movie3);
14                 context.Movies.Add(movie4);
15                 context.SaveChanges();
16             }
17 
18             using (var context = new Recipe13Context())
19             {
20                 // 經過ReleaseType和Rating過慮
21                 // 建立匿名類型集合
22                 var cats = from c in context.Categories
23                            where c.ReleaseType == "DVD"
24                            select new
25                                {
26                                    category = c,
27                                    movies = c.Movies.Where(m => m.Rating == "PG-13")
28                                };
29 
30                 Console.WriteLine("PG-13 Movies Released on DVD");
31                 Console.WriteLine("============================");
32                 foreach (var cat in cats)
33                 {
34                     var category = cat.category;
35                     Console.WriteLine("Category: {0}", category.Name);
36                     foreach (var movie in cat.movies)
37                     {
38                         Console.WriteLine("\tMovie: {0}", movie.Name);
39                     }
40                 }
41             }
42 
43             Console.WriteLine("Press <enter> to continue...");
44             Console.ReadLine();

代碼清單5-36輸出以下:

PG-13 Movies Released on DVD
============================
Category: Science Fiction
        Movie: Return to the Moon
        Movie: Saturday Nights    

原理

  代碼清單5-36,先建立並初始化categoryes和movies。爲了保持簡短,咱們只建立了兩個目錄和4部電影。

  在查詢中,咱們建立一個匿名類型的集合,它包含category實例,和在目錄中過濾後的movies實例。該查詢也過濾了目錄集合,只獲取發行類型爲「DVD"的目錄。在示例中,只有一個目錄的發行類型爲「DVD"。這裏咱們依賴關係跨度(relationship span)將movies附加到categories。

  這個方法憑藉匿名對象幫助咱們繞開了預先加載中的限制,預先加載不容許咱們過濾預先加載的實體集合。注意,正如前面小節中的示例演示的那樣,當咱們顯式加載時,咱們能過慮一個預先加載的實體集合。記住,匿名類型對象的生命週期範圍只在建立它的方法中,方法不能返回匿名類型。若是咱們目標是返回一個應用後面要處理的實體集,那麼咱們須要建立一個確切的類型來存放數據,而後將它返回。在咱們的示例中,這個確切的類應該是一個簡單的類,它只建立兩個屬性:Category 和一個Movies集合。

 

5-14  修改外鍵關聯

問題

  你想修改外鍵關聯。

解決方案

  實體框架提供了兩種方式來修改外鍵關聯,你能夠將一個關聯的實體添加到導航屬性集合或者賦值給導航屬性。你還能夠將關聯實體的鍵值設置成外鍵值。

  假設你有如圖5-29所示的模型。

圖5-29 一個包含client和Invoice的模型


   按下面的步驟,使用兩種不一樣的方式,修改client實體和nvoice實體間的外鍵關聯:

    一、右鍵你的項目,選擇Add(添加) ➤ADO.NET Entity Data Model(ADO.NET 實體數據模型)。導入Client和Invoice表。確保勾上選項 Include foreign key columns in the model(包含外鍵列到模型),它默認是勾選上的。如圖5-30所示。這樣會從數據庫中導入外鍵關聯,它不是多對多關係。

圖5-30 勾上選項 Include foreign key columns in the model(包含外鍵列到模型)將會爲數據中的關係建立外鍵關聯。數據中的關係不是多對多關係。

     二、使用代碼清單5-37演示修改外鍵關聯的方法。

代碼清單5-37. 演示修改外鍵關聯

 1  using (var context = new EFRecipesEntities())
 2             {
 3                 var client1 = new Client {Name = "Karen Standfield", ClientId = 1};
 4                 var invoice1 = new Invoice {InvoiceDate = DateTime.Parse("4/1/10"), Amount = 29.95M};
 5                 var invoice2 = new Invoice {InvoiceDate = DateTime.Parse("4/2/10"), Amount = 49.95M};
 6                 var invoice3 = new Invoice {InvoiceDate = DateTime.Parse("4/3/10"), Amount = 102.95M};
 7                 var invoice4 = new Invoice {InvoiceDate = DateTime.Parse("4/4/10"), Amount = 45.99M};
 8 
 9                 // 添加一個invoice到client的導航屬性集合Invoices
10                 client1.Invoices.Add(invoice1);
11 
12                 //直接分配一個外鍵值
13                 invoice2.ClientId = 1;
14 
15                 //使用一個「假」實體附加一存在的行
16                 context.Database.ExecuteSqlCommand("insert into chapter5.client values (2, 'Phil Marlowe')");
17                 var client2 = new Client {ClientId = 2};
18                 context.Clients.Attach(client2);
19                 invoice3.Client = client2;
20 
21                 // 使用Client引用
22                 invoice4.Client = client1;
23 
24                 //保存更改
25                 context.Clients.Add(client1);
26                 context.Invoices.Add(invoice2);
27                 context.Invoices.Add(invoice3);
28                 context.Invoices.Add(invoice4);
29                 context.SaveChanges();
30             }
31 
32             using (var context = new EFRecipesEntities())
33             {
34                 foreach (var client in context.Clients)
35                 {
36                     Console.WriteLine("Client: {0}", client.Name);
37                     foreach (var invoice in client.Invoices)
38                     {
39                         Console.WriteLine("\t{0} for {1}", invoice.InvoiceDate.ToShortDateString(),
40                                           invoice.Amount.ToString("C"));
41                     }
42                 }
43             }
44 
45             Console.WriteLine("Press <enter> to continue...");
46             Console.ReadLine();

  代碼清單5-37的輸出以下:

Client: Karen Standfield
        4/1/2010 for $29.95
        4/4/2010 for $45.99
        4/2/2010 for $49.95
Client: Phil Marlowe
        4/3/2010 for $102.95

原理

  實體框架支持獨立關聯和外鍵關聯。對於獨立關聯,由關聯間的實體自行跟蹤,修改關聯的惟一方式是經過修改對象引用

  對於外鍵關聯,你能夠經過修改對象引用,或是直接修改外鍵屬性值來修改關聯。外鍵關聯不能用做多對多關係

注意  記住,外鍵關聯簡單易用,它是默認方法,也是實體框架開發團隊推薦的方法。除非你有具體的業務要求使用獨立關聯。不然請使用外鍵關聯。

  表5-1展現了獨立關聯和外鍵關聯之間的主要區別。

表5-1. 獨立關聯和外鍵關聯之間的區別

 

 

 至此第5章結束,下篇咱們將進入第六章,感謝你的閱讀。以爲有幫助的話,點擊下邊的推薦以示支持。謝謝!

 

 

 

實體框架交流QQ羣:  458326058,歡迎有興趣的朋友加入一塊兒交流

謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/VolcanoCloud/

相關文章
相關標籤/搜索