在Entity Framework中使用儲存過程
本篇文章透過例項的方式,討論兩個在EF使用儲存過程的主題:如何透過實體和儲存過程的對映實現邏輯刪除;對於具有自增長型別主鍵的資料表,在進行新增操作的時候如何將正確的值反映在實體物件上。
目錄
一、基於邏輯刪除的資料表和儲存過程定義
二、如何過濾邏輯刪除記錄
三、具有自增長列的儲存過程定義
四、透過Result Columns Binding將結果集的列於實體屬性進行繫結
一、基於邏輯刪除的資料表和儲存過程定義
較之物理刪除(記錄徹底從資料表中清除掉),邏輯刪除則繼續保留該資料,只是為之進行一個刪除標記,表明該記錄已經被“刪除”了。比如透過下面的SQL,我建立了一個簡單的表T_CONTACT表,其中BIT型別的欄位IS_DELETED就為這個“刪除標記”。
1: CREATE TABLE T_CONTACT
2: (
3: [ID] VARCHAR(50) PRIMARY KEY,
4: [NAME] NVARCHAR(50) NOT NULL,
5: [IS_DELETED] BIT NOT NULL
6: )
那麼當我們進行刪除操作的儲存過程中,不是就行Delete操作,而是進行Update操作,將IS_DELETED的值設定成1即可,這樣的儲存過程定義如下:
1: CREATE PROCEDURE P_CONTACT_D
2: (@p_id VARCHAR(50))
3: AS
4: BEGIN
5: UPDATE T_CONTACT
6: SET IS_DELETED = 1
7: WHERE ID = @p_id
8: END
二、如何過濾邏輯刪除記錄
開啟VS,透過匯入該資料表和CUD儲存過程建立.edmx模型,同時修改概念模型實體名稱(比如T_CONTACT改成Contact)和屬性名稱。並刪除屬性IS_DELETED,最終得到如右圖所示的.edmx模型。然後為Contact實體對映CUD儲存過程和相關引數,其中刪除操作的儲存過程已經定義在上面。
然後,你需要考慮這樣一個問題:由於我們進行的是邏輯刪除,被“刪除”的記錄依然儲存於資料庫中。當你進行資料查詢的時候,如果沒有顯式設定IS_DELETED=0為篩選條件的情況下,所有被“刪除”的記錄依然會被返回。進一步地講,由於我們在.edmx模型的概念實體Contact中,已經將IS_DELETED刪除掉了,所以我們在程式中不可能設定這樣一個額外的篩選條件。
實際上EF為你考慮到了這一點,你可以在直接透過EF設計器設定這樣一個篩選條件。在當前實體被選中的情況下,進入Mapping Details介面,你會發現在於資料庫表的對映中具有一個
基於上面的設定編寫如下的程式碼,先新增3條Contact記錄,然後將它們刪除。並在刪除前後根據ID獲取對應記錄,列印出來以驗證上面設計的篩選條件是否真的有效。
1: static void Main(string[] args)
2: {
3: string[] contractIds = new string[] {
4: Guid.NewGuid().ToString(),
5: Guid.NewGuid().ToString(),
6: Guid.NewGuid().ToString() };
7: using (EFExtensionsEntities context = new EFExtensionsEntities())
8: {
9: Contact contact1 = Contact.CreateContact(contractIds[0], "Zhang San");
10: Contact contact2 = Contact.CreateContact(contractIds[1], "Li Si");
11: Contact contact3 = Contact.CreateContact(contractIds[2], "Wang Wu");
12: context.Contacts.AddObject(contact1);
13: context.Contacts.AddObject(contact2);
14: context.Contacts.AddObject(contact3);
15: context.SaveChanges();
16:
17: Console.WriteLine("Before Delete...");
18: foreach(var contact in context.Contacts.Where(c=>contractIds.Contains(c.ID)))
19: {
20: Console.WriteLine("{0}: {1}", contact.ID, contact.Name);
21: }
22: foreach (var contact in context.Contacts.Where(c => contractIds.Contains(c.ID)))
23: {
24: context.Contacts.DeleteObject(contact);
25: }
26: context.SaveChanges();
27:
28: Console.WriteLine("After Delete...");
29: foreach (var contact in context.Contacts.Where(c => contractIds.Contains(c.ID)))
30: {
31: Console.WriteLine("{0}: {1}", contact.ID, contact.Name);
32: }
33: }
34: }
下面是輸出結果,可見被刪除的記錄真的不曾出現在查詢結果中。
1: Before Delete...
2: 4032d301-80cb-4e6d-a3e7-f5560e918b4a: Li Si
3: 69b8bdbb-4714-4d68-9619-f4cd587c37ef: Zhang San
4: dbadfef9-d6d2-466b-8eae-392f1d731c14: Wang Wu
5: After Delete...
實際上在資料庫中,這三條資料依然存在,只是邏輯刪除標識欄位IS_DELETED被標記為1。
三、具有自增長列的儲存過程定義
接下來我們來討論另一個常見的場景:如果一個表中存在一個自增長列作為該表的主鍵,當我們透過提交對應的實體物件進行記錄新增操作時,資料庫中真正的鍵值如何返回並賦值給該實體物件。為了模擬這個場景,我重新定義了資料表T_CONTACT的定義,將ID列定義成自增長列。建立該表對應的DDL如下所示:
1: CREATE TABLE T_CONTACT
2: (
3: [ID] INT IDENTITY(1,1) PRIMARY KEY,
4: [NAME] NVARCHAR(50) NOT NULL,
5: [IS_DELETED] BIT NOT NULL
6: )
如果你希望真正的ID能夠返回給被新增的Contact物件,在儲存過程中完成新增操作後,應該透過SELECT語句將對應的真實ID返回,這樣的儲存過程應該這樣來寫:
1: CREATE PROCEDURE [P_CONTACT_I]
2: @p_name NVARCHAR(50)
3: AS
4: BEGIN
5: INSERT INTO T_CONTACT(NAME, IS_DELETED)
6: VALUES( @p_name, 0)
7:
8: SELECT [ID]
9: FROM T_CONTACT
10: WHERE [ID] = SCOPE_IDENTITY()
11: END
四、透過Result Columns Binding將結果集的列於實體屬性進行繫結
在.edmx模型的設計器中,點選右鍵並再上下文選單中選擇"Update Model From Database…”,讓VS重新載入我們修改過的儲存過程,然後你需要對儲存過程對映關係進行重新設定。由於ID的資料型別改變了,你需要修正Update和Delete儲存過程,並改變Contact的ID屬性的資料型別從String程式設計Int32。
為了讓儲存過程中SELECT語句返回的結果集體現在被提交的Contact物件上,你需要設定列名(或者透過AS運算子設定的別名)與實體型別的屬性之間的對映關係。這個關係的定義包含在儲存過程對映的Result Columns Binding列表中。如下圖所示,我設定了儲存過程返回列ID和Contact屬性ID之間的對映關係。
基於最新的.edmx模型,我們編寫如下的程式碼,分別建立三個Contact記錄。從最終的執行結果,我們可以清晰地看到,從資料庫中返回的真實ID反映在了被新增的Contact物件上了。
1: static void Main(string[] args)
2: {
3: using (EFExtensionsEntities context = new EFExtensionsEntities())
4: {
5: Contact contact = new Contact { Name = "Zhang San" };
6: context.Contacts.AddObject(contact);
7: context.SaveChanges();
8: Console.WriteLine("{0}: {1}", contact.ID, contact.Name);
9:
10: contact = new Contact { Name = "Li Si" };
11: context.Contacts.AddObject(contact);
12: context.SaveChanges();
13: Console.WriteLine("{0}: {1}", contact.ID, contact.Name);
14:
15: contact = new Contact { Name = "Wang Wu" };
16: context.Contacts.AddObject(contact);
17: context.SaveChanges();
18: Console.WriteLine("{0}: {1}", contact.ID, contact.Name);
19: }
20: }
執行結果:
1: 10: Zhang San
2: 11: Li Si
3: 12: Wang Wu
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3244/viewspace-2806438/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Entity Framework 6 Code First新特性:支援儲存過程Framework儲存過程
- Entity Framework Code First執行SQL語句、檢視及儲存過程FrameworkSQL儲存過程
- 在儲存過程A中呼叫儲存過程B的結果儲存過程
- 關於Entity Freamwork 儲存過程操作儲存過程
- 在儲存過程中寫truncate table儲存過程
- 使用儲存過程儲存過程
- ADO中sqlserver儲存過程使用SQLServer儲存過程
- MySQL儲存過程中如何使用ROLLBACKMySql儲存過程
- SQL Server儲存過程中raiserror的使用SQLServer儲存過程AIError
- ADO中sqlserver儲存過程使用 (轉)SQLServer儲存過程
- 在C#中使用儲存過程的方法C#儲存過程
- Sqlserver中的儲存過程SQLServer儲存過程
- PB中呼叫儲存過程儲存過程
- 儲存過程中拼接字串儲存過程字串
- java中呼叫儲存過程Java儲存過程
- Mysql 儲存過程的使用MySql儲存過程
- 儲存過程中使用cursor儲存過程
- 在Oracle中查詢儲存過程和函式Oracle儲存過程函式
- 在儲存過程中建立表的兩種方法儲存過程
- 儲存過程中巢狀儲存過程的變數執行方式儲存過程巢狀變數
- Hibernate中怎麼使用儲存過程呢?儲存過程
- 使用儲存過程(PL/SQL)向資料庫中儲存BLOB物件儲存過程SQL資料庫物件
- MySQL儲存過程詳解 mysql 儲存過程MySql儲存過程
- PetaPoco在.net專案中的簡單使用(儲存過程篇)儲存過程
- Oracle在儲存過程中呼叫其他使用者的表授權Oracle儲存過程
- 儲存過程儲存過程
- jsp中呼叫儲存過程JS儲存過程
- 儲存過程中慎用 execute immediate儲存過程
- java中呼叫ORACLE儲存過程JavaOracle儲存過程
- Git.Framework 框架隨手記--儲存過程簡化GitFramework框架儲存過程
- 在 SQL Server 的儲存過程中呼叫 Com 元件 (轉)SQLServer儲存過程元件
- Laravel 中使用 MySQL 儲存過程LaravelMySql儲存過程
- mysql 遊標的使用(儲存過程)MySql儲存過程
- oracle 儲存過程遊標的使用Oracle儲存過程
- Oracle中定義package以及儲存過程的使用OraclePackage儲存過程
- SQL 儲存過程裡呼叫另一個儲存過程SQL儲存過程
- MySQL儲存過程詳解 mysql 儲存過程linkMySql儲存過程
- Oracle儲存過程乾貨(一):儲存過程基礎Oracle儲存過程