問題html
你想使用多個條件爲實體過濾表中的行。數據庫
解決方案瀏覽器
假設你有一張處理網站訂單的表,如圖6-13所示。app
圖6-13 表WebOrder包含網站訂單的信息框架
假設咱們有這樣一個業務需求,WebOrder中的實例爲,2012年之後的,2010年到2012年之間未刪除的,2010年之前的訂單金額大於200美圓的。這樣的複雜過濾條件不能使用映射詳細信息窗口中有限制的條件來建立了。 有一種實現方法是使用QueryView。按下面的步驟,使用QueryView來爲這個實體和知足業務須要的條件建模:編輯器
一、在你的項目中添加一個ADO.NET Entity Data Model(ADO.NET實體數據模型),並導入表WebOrder。使用代碼清單6-27中的代碼建立存儲過程。接下來的兩步,咱們將爲WebOrder實體映射insert,update和delete動做。函數
代碼清單6-27. 在數據庫中爲WebOrder實體定義的Insert,Update和Delete動做工具
1 create procedure [Chapter6].[InsertOrder] 2 (@CustomerName varchar(50),@OrderDate date,@IsDeleted bit,@Amount decimal) 3 as 4 begin 5 insert into chapter6.WebOrder (CustomerName, OrderDate, IsDeleted, Amount) 6 values (@CustomerName, @OrderDate, @IsDeleted, @Amount) 7 select SCOPE_IDENTITY() as OrderId 8 end 9 go 10 create procedure [Chapter6].[UpdateOrder] 11 (@CustomerName varchar(50),@OrderDate date,@IsDeleted bit, 12 @Amount decimal, @OrderId int) 13 as 14 begin 15 update chapter6.WebOrder set CustomerName = @CustomerName, 16 OrderDate = @OrderDate,IsDeleted = @IsDeleted,Amount = @Amount 17 where OrderId = @OrderId 18 end 19 go 20 create procedure [Chapter6].[DeleteOrder] 21 (@OrderId int) 22 as 23 begin 24 delete from Chapter6.WebOrder where OrderId = @OrderId 25 end
二、右鍵設計器,並選擇Update Model from Database(從數據庫更新模型)。在更新嚮導中,選擇存儲過程InsertOrder,UpdateOrder和DeleteOrder。學習
三、選擇WebOrder實體,並查看Mapping Details window(映射詳細信息窗口)。單擊Map Entity to Function(映射實體到函數)按鈕。這個按鈕是在映射詳細信息窗口左邊最下邊的一個按鈕。映射Insert、Update和Delete動做到存儲過程。prperty/parameter(屬性/參數)映射會自動填入。然而,存儲過程InsertOrder的返回值必須映射到OrderId屬性。這是實體框架用於在插入操做後獲取標識列OrderId值的途徑。正確映射如圖6-14所示。網站
圖6-14 存儲過程/動做映射詳細信息
四、在映射詳細信息窗口中選擇映射表(最上邊的按鈕)。刪除WebOrder表的映射。咱們將在後面使用QueryView來映射;
在解決方案瀏覽器中右鍵.edmx文件,選擇Open With(打開方式) ➤XML Editor(XML文本編輯器)。在C-S映射層,將代碼清單6-28中的查詢視圖(QueryView)插入到標籤<EntitySetMapping>中,QueryView將映射實體WebOrder。
當心!C-S映射層的修改會在下一次從數據庫更新模型時丟失。
代碼清單6-28. 使用QueryView爲WebOrder表映射實體集
1 <EntitySetMapping Name="WebOrders"> 2 <QueryView> 3 select value 4 Apress.EF6Recipes.BeyondModelingBasics.Recipe10.WebOrder(o.OrderId, 5 o.CustomerName,o.OrderDate,o.IsDeleted,o.Amount) 6 from ApressEF6RecipesBeyondModelingBasicsRecipe10StoreContainer.WebOrder as o 7 where (o.OrderDate > datetime'2012-01-01 00:00') || 8 (o.OrderDate between cast('2010-01-01' as Edm.DateTime) and 9 cast('2012-01-01' as Edm.DateTime) and !o.IsDeleted) || 10 (o.Amount > 200 and o.OrderDate < 11 cast('2010-01-01' as Edm.DateTime)) 12 </QueryView> 13 </EntitySetMapping>
原理
QueryView是一種只讀映射,它能夠用來代替實體框架爲咱們提供的默認映射。當QueryView在映射層標籤<EntitySetMapping>中時,它將映射存儲層定義的表和在概念模型層中定義的實體。當它在標籤<AssociationSetMapping>中時,它將映射存儲層中的關係和概念模型中的關聯。QueryView的一般用法是,用在標籤<AssociationSetMapping>中,用它來實現基於條件的,且不能經過默認的條件映射來實現的繼承映射。
QueryView使用Entity SQL來表示,QueryView只能查詢在概念模型定義的實體。另外,QueryView中的eSQL不支持gourp by和group聚合。
當實體使用QueryView來映射時,實體框架對這精確的映射實現渾然不知。這是由於實體框架不知道底層的表和列用來建立實體的實例,它不能產生適當的存儲層動做來插入、更新或者刪除實體。實體被實例化後,實體框架也不會進行跟蹤。它不知道底層如何修改實體。
實現插入、更新和刪除動做的責任落到了開發員人的頭上,這些動做能夠直接在.edmx文件中實現,也能夠在數據庫使用存儲過程來實現。爲了管理這些動做的存儲過程,你須要建立<ModificationFunctionMapping>節。咱們在第四步使用設計器而不是直接修改.edmx文件的方式來實現的。
若是使用QueryView映射的實體與別的實體之間有關聯,這些關聯及其關聯的實體都須要使用QueryView來映射。固然,這會變得至關麻煩。QueryView是一個強有力的工具,但當很快就會成爲咱們的負擔。
下面是QueryView的常見使用場景:
一、定義一個不被支持的過濾條件,好比:大於,小於等等;
二、映射基於除了is null,not null或者equal to條件的繼承;
三、映射一列計算後的列,或是從表中返加列的子集,或是爲了改變限制或類型爲Data的列,例如,讓它爲可空類型,將一字符串列顯現爲整型;
四、映射基於不一樣主鍵和外鍵的TPT繼承映射;
五、映射存儲層相同的列到概念模型中不一樣的類型;
六、映射多個類型到同一張表;
代碼清單6-28中,QueryView裏包含一個Entity SQL語句,它包含三個部分。第一個部分是select從句,使用構造函數實例化一個WebOrder實例。構造函數獲取屬性值的順序跟咱們在概念模型中定義的順序一至,如代碼清單6-29所示。
代碼清單6-29.概念模型中WebOrder實體的定義
<EntityType Name="WebOrder"> <Key> <PropertyRef Name="OrderId" /> </Key> <Property Name="OrderId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> <Property Name="CustomerName" Type="varchar" Nullable="false" MaxLength="255" /> <Property Name="OrderDate" Type="datetime" Nullable="false" /> <Property Name="IsDeleted" Type="bit" Nullable="false" /> <Property Name="Amount" Type="money" /> </EntityType>
注意,在代碼清單6-28中的Entity SQL中,在建立WebOrder實體的實例時,咱們徹底限定命名空間EFRecipesModel。咱們在from從句中一樣限定了存儲容器EFRecipesModelStoreContainer。
在Entity SQL表達式中的最後一節,包含了where從句,它是咱們這個示例使用QueryView的緣由。雖然where從句能夠任意的複雜,但它受上面看到的QueryView中的Entity SQL限制。
代碼清單6-30演示了,在模型中插入和獲取WebOrders。
代碼清單6-30.插入和獲取WebOrder實體
1 using (var context = new Recipe10Context()) 2 { 3 var order = new WebOrder 4 { 5 CustomerName = "Jim Allen", 6 OrderDate = DateTime.Parse("5/3/2012"), 7 IsDeleted = false, 8 Amount = 200 9 }; 10 context.WebOrders.Add(order); 11 order = new WebOrder 12 { 13 CustomerName = "John Stevens", 14 OrderDate = DateTime.Parse("1/1/2011"), 15 IsDeleted = false, 16 Amount = 400 17 }; 18 context.WebOrders.Add(order); 19 order = new WebOrder 20 { 21 CustomerName = "Russel Smith", 22 OrderDate = DateTime.Parse("1/3/2011"), 23 IsDeleted = true, 24 Amount = 500 25 }; 26 context.WebOrders.Add(order); 27 order = new WebOrder 28 { 29 CustomerName = "Mike Hammer", 30 OrderDate = DateTime.Parse("6/3/2013"), 31 IsDeleted = true, 32 Amount = 1800 33 }; 34 context.WebOrders.Add(order); 35 order = new WebOrder 36 { 37 CustomerName = "Steve Jones", 38 OrderDate = DateTime.Parse("1/1/2008"), 39 IsDeleted = true, 40 Amount = 600 41 }; 42 context.WebOrders.Add(order); 43 context.SaveChanges(); 44 } 45 46 using (var context = new Recipe10Context()) 47 { 48 Console.WriteLine("Orders"); 49 Console.WriteLine("======"); 50 foreach (var order in context.WebOrders) 51 { 52 Console.WriteLine("\nCustomer: {0}", order.CustomerName); 53 Console.WriteLine("OrderDate: {0}", order.OrderDate.ToShortDateString()); 54 Console.WriteLine("Is Deleted: {0}", order.IsDeleted.ToString()); 55 Console.WriteLine("Amount: {0:C}", order.Amount); 56 } 57 }
代碼清單6-30的輸出以下。注意,只有知足咱們在QueryView中,使用Entity SQL表達式定義的條件的customers才被顯示。
Orders... Customer: John Stevens Order Date: 1/1/2011 Is Deleted: False Amount: $400.00 Customer: Jim Allen Order Date: 5/3/2012 Is Deleted: False Amount: $200.00 Customer: Mike Hammer Order Date: 6/3/2013 Is Deleted: True Amount: $1,800.00
實體框架交流QQ羣: 458326058,歡迎有興趣的朋友加入一塊兒交流
謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/VolcanoCloud/