Entity
Framework快速入門--直接修改(簡要介紹ObjectContext處理機制)
在介紹Entity Framework的修改實體到資料庫的方法之前呢,我們先簡要的介紹一下ObjectContext的處理機制。
1、ObjectContext的處理機制
ObjectContext是Entity
Framework封裝了資料庫訪問的上下文,以及實體的映射關係中繼資料資訊等。EF幫我們封裝好了這麼一個統一的介面。讓我們所有的操作都只通過這個一個實體上下文就可以實現了增刪查改等所有對應資料庫的操作。當然,我們要瞭解EF的產生SQL的機制我們才能更好的使用EF幫我們產生效率更高的SQL指令碼。
看一個執行個體:所示項目與實體模型圖(一個簡單的例子)
然後看下面一段代碼:
static void Main(string[] args)
{
SchoolDBEntities schoolDB = new SchoolDBEntities();
Student student = new Student();
student.Address = "北京上地";
student.Name = "飛龍";
student.Phone = "110";
schoolDB.Student.AddObject(student);
schoolDB.SaveChanges();
}
就是簡單的網資料庫中添加一條資料。我們在上面代碼紅色背景地方加上斷點【schoolDB是EF自動幫我們產生的繼承自ObjectContext的上下文】並對schoolDB進行快速監視。如下:
由於圖篇幅有限,只截取了部分視圖。在此我就簡單介紹一下幾個比較關鍵的屬性。
(1):Connection,相信大家一下子就能猜到,當然它封裝了EF串連資料庫的XxxConnection(如:SqlConnection)。這個就不囉嗦了。
(2):ObjectStateManage,它職責是維護實體類型執行個體和關係執行個體的對象狀態和標識管理。也是EF上下文中非常重要的一個屬性。它幫我們把添加的實體放到添加隊列裡,把修改的實體放到修改的隊列裡,當然還有刪除等的。每個實體做了修改時,EF幫我們把實體放到相應的隊列中並修改相應的實體的狀態(EntityState),當調用ObjectContext的SaveChanges()方法時,EF根據隊列的情況以及EDMX中繼資料映射的資訊產生最終的SQL指令碼。
(3):中我們看到_addedEntityStore就是我們剛才所說的添加實體的一個集合,而且這裡面的每個實體對應的
EntityState(標誌實體在記憶體中的狀態,是個Enum類型)都是Added狀態,當然這表示添加,最終產生SQL時是Insert Into...
當然還有刪除的隊列、修改的隊列這個大家自己看一下就可以了。
(4):EntityState,實體物件的狀態。標誌我們開發人員對實體的相應的操作,如下表格是實體的相關狀態以及說明(摘自MSDN)
| 成員名稱 |
說明 |
| Detached |
對象存在,但沒有被跟蹤。 在建立實體之後、但將其添加到物件內容之前,該實體處於此狀態。 An entity is also in this state after it has been removed from the context by calling the Detach method or if it is loaded by using a NoTrackingMergeOption. 沒有 ObjectStateEntry 執行個體與狀態為 Detached 的對象關聯。 |
| Unchanged |
自對象附加到上下文中後,或自上次調用 SaveChanges 方法後,此對象尚未經過修改。 |
| Added |
對象為新對象,並且已添加到物件內容,但尚未調用 SaveChanges 方法。 在儲存更改後,對象狀態將更改為 Unchanged。 狀態為 Added 的對象在 ObjectStateEntry 中沒有原始值。 |
| Deleted |
對象已從物件內容中刪除。 在儲存更改後,對象狀態將更改為 Detached。 |
| Modified |
對象上的一個純量屬性已更改,但尚未調用 SaveChanges 方法。 在不帶變更追蹤代理的 POCO 實體中,調用 DetectChanges 方法時,已修改屬性的狀態將更改為 Modified。 在儲存更改後,對象狀態將更改為 Unchanged。 |
註:
物件內容必須知道對象狀態才能將更改儲存回資料來源。 ObjectStateEntry Object Storage Service EntityState 資訊。 ObjectContext 的 SaveChanges 方法根據每個對象的 EntityState 處理附加到內容相關的實體和更新資料來源。 有關更多資訊,請參見Adding, Modifying,
and Deleting Objects。
物件內容中的對象狀態由 ObjectStateManager 管理。 若要尋找對象的狀態,請調用以下 ObjectStateManager 方法之一:TryGetObjectStateEntry、GetObjectStateEntry 或GetObjectStateEntries。 ObjectStateEntry 的 State 屬性定義該對象的狀態。
總結:
EF是通過針對開發人員對實體做的修改,直接維護
ObjectContext的執行個體中的實體操作集合并對單個實體對應的狀態進行修改。最終根據此集合以及狀態再加上表實體映射的中繼資料資訊產生最終的
SQL指令碼。所以,我們在對應多個ObjectContext執行個體進行操作時要注意,調用執行個體自己的SaveChanges()方法時,它只會對自己執行個體記憶體空間的操作映射回資料庫,而其他ObjectContext執行個體中的實體集合的修改都不受影響。而且EF自動幫我們做了緩衝的處理,當我們第一次查詢某個實體時它會自動幫我們從資料庫取出資料,並裝配成實體類交給我們開發人員,當第二次擷取相同資料時,它會先從緩衝中尋找,如果已經存在資料了就立即返回,不會查詢資料庫。這就造成了一個問題,當ObjectContext執行個體如果一直不被銷毀,那它的緩衝會一直膨脹下去,所以在開發應用時,用單例直接處理EF的上下文也不是很合適。最好的方式應該是
在一次處理請求中(web開發)使用同一個ObjectContext執行個體即可,避免了多個上下文執行個體的維護,而且也不至於上下文執行個體日益膨脹。
2、EF實體中的修改
說到現在才進入正題,那我們怎麼來進行修改呢?
不推薦方式一:
思路:先從ObjectContext取出實體,然後將前台傳過來的DTO屬性對應賦值到我們的實體上,然後調用ObjectContext的保證修改方法。
但是這種方式是最不提倡的,因為這樣每次修改前都得先將資料查出來,經過SqlProfiler追蹤,這麼一個操作要對資料庫進行兩次的串連。這是不可忍受的!
推薦方式二:
思路:無需先查出實體,因為我們知道EF通過
ObjectStateManage來控制添加、修改、刪除隊列以及實體的狀態,我們所有可以通過在直接將DTO轉化成實體,然後將實體對應的隊列中,並且我們手動的將實體的狀態處理好,再調用ObjectContext的保證修改方法,這樣就避免了先查詢後修改,兩次資料庫連接的問題了。執行個體代碼如下:
static void Main(string[] args)
{
SchoolDBEntities schoolDB = new SchoolDBEntities();
//假設:網路傳一個StudentDTO過來 ,將此DTO轉化成 資料庫實體
Student student = new Student();
student.Id = 1;// 假設DTO傳過來的值,主鍵必須存在,不然會報錯的
student.Address = "北京上地1";
student.Name = "飛龍1";
student.Phone = "1101";
//先將實體附加到實體上下文中
schoolDB.Student.Attach(student);
//手動修改實體的狀態
schoolDB.ObjectStateManager.ChangeObjectState(student, EntityState.Modified);
//儲存回資料庫
schoolDB.SaveChanges();
}
總算把這塊描述完了!希望對初學者有用!歡迎高手指正錯誤!
技術改變世界,奮鬥改變人生!
Entity
Framework快速入門--索引貼
在介紹Entity Framework的修改實體到資料庫的方法之前呢,我們先簡要的介紹一下ObjectContext的處理機制。
1、ObjectContext的處理機制
ObjectContext是Entity
Framework封裝了資料庫訪問的上下文,以及實體的映射關係中繼資料資訊等。EF幫我們封裝好了這麼一個統一的介面。讓我們所有的操作都只通過這個一個實體上下文就可以實現了增刪查改等所有對應資料庫的操作。當然,我們要瞭解EF的產生SQL的機制我們才能更好的使用EF幫我們產生效率更高的SQL指令碼。
看一個執行個體:所示項目與實體模型圖(一個簡單的例子)
然後看下面一段代碼:
static void Main(string[] args)
{
SchoolDBEntities schoolDB = new SchoolDBEntities();
Student student = new Student();
student.Address = "北京上地";
student.Name = "飛龍";
student.Phone = "110";
schoolDB.Student.AddObject(student);
schoolDB.SaveChanges();
}
就是簡單的網資料庫中添加一條資料。我們在上面代碼紅色背景地方加上斷點【schoolDB是EF自動幫我們產生的繼承自ObjectContext的上下文】並對schoolDB進行快速監視。如下:
由於圖篇幅有限,只截取了部分視圖。在此我就簡單介紹一下幾個比較關鍵的屬性。
(1):Connection,相信大家一下子就能猜到,當然它封裝了EF串連資料庫的XxxConnection(如:SqlConnection)。這個就不囉嗦了。
(2):ObjectStateManage,它職責是維護實體類型執行個體和關係執行個體的對象狀態和標識管理。也是EF上下文中非常重要的一個屬性。它幫我們把添加的實體放到添加隊列裡,把修改的實體放到修改的隊列裡,當然還有刪除等的。每個實體做了修改時,EF幫我們把實體放到相應的隊列中並修改相應的實體的狀態(EntityState),當調用ObjectContext的SaveChanges()方法時,EF根據隊列的情況以及EDMX中繼資料映射的資訊產生最終的SQL指令碼。
(3):中我們看到_addedEntityStore就是我們剛才所說的添加實體的一個集合,而且這裡面的每個實體對應的
EntityState(標誌實體在記憶體中的狀態,是個Enum類型)都是Added狀態,當然這表示添加,最終產生SQL時是Insert Into...
當然還有刪除的隊列、修改的隊列這個大家自己看一下就可以了。
(4):EntityState,實體物件的狀態。標誌我們開發人員對實體的相應的操作,如下表格是實體的相關狀態以及說明(摘自MSDN)
| 成員名稱 |
說明 |
| Detached |
對象存在,但沒有被跟蹤。 在建立實體之後、但將其添加到物件內容之前,該實體處於此狀態。 An entity is also in this state after it has been removed from the context by calling the Detach method or if it is loaded by using a NoTrackingMergeOption. 沒有 ObjectStateEntry 執行個體與狀態為 Detached 的對象關聯。 |
| Unchanged |
自對象附加到上下文中後,或自上次調用 SaveChanges 方法後,此對象尚未經過修改。 |
| Added |
對象為新對象,並且已添加到物件內容,但尚未調用 SaveChanges 方法。 在儲存更改後,對象狀態將更改為 Unchanged。 狀態為 Added 的對象在 ObjectStateEntry 中沒有原始值。 |
| Deleted |
對象已從物件內容中刪除。 在儲存更改後,對象狀態將更改為 Detached。 |
| Modified |
對象上的一個純量屬性已更改,但尚未調用 SaveChanges 方法。 在不帶變更追蹤代理的 POCO 實體中,調用 DetectChanges 方法時,已修改屬性的狀態將更改為 Modified。 在儲存更改後,對象狀態將更改為 Unchanged。 |
註:
物件內容必須知道對象狀態才能將更改儲存回資料來源。 ObjectStateEntry Object Storage Service EntityState 資訊。 ObjectContext 的 SaveChanges 方法根據每個對象的 EntityState 處理附加到內容相關的實體和更新資料來源。 有關更多資訊,請參見Adding, Modifying,
and Deleting Objects。
物件內容中的對象狀態由 ObjectStateManager 管理。 若要尋找對象的狀態,請調用以下 ObjectStateManager 方法之一:TryGetObjectStateEntry、GetObjectStateEntry 或GetObjectStateEntries。 ObjectStateEntry 的 State 屬性定義該對象的狀態。
總結:
EF是通過針對開發人員對實體做的修改,直接維護
ObjectContext的執行個體中的實體操作集合并對單個實體對應的狀態進行修改。最終根據此集合以及狀態再加上表實體映射的中繼資料資訊產生最終的
SQL指令碼。所以,我們在對應多個ObjectContext執行個體進行操作時要注意,調用執行個體自己的SaveChanges()方法時,它只會對自己執行個體記憶體空間的操作映射回資料庫,而其他ObjectContext執行個體中的實體集合的修改都不受影響。而且EF自動幫我們做了緩衝的處理,當我們第一次查詢某個實體時它會自動幫我們從資料庫取出資料,並裝配成實體類交給我們開發人員,當第二次擷取相同資料時,它會先從緩衝中尋找,如果已經存在資料了就立即返回,不會查詢資料庫。這就造成了一個問題,當ObjectContext執行個體如果一直不被銷毀,那它的緩衝會一直膨脹下去,所以在開發應用時,用單例直接處理EF的上下文也不是很合適。最好的方式應該是
在一次處理請求中(web開發)使用同一個ObjectContext執行個體即可,避免了多個上下文執行個體的維護,而且也不至於上下文執行個體日益膨脹。
2、EF實體中的修改
說到現在才進入正題,那我們怎麼來進行修改呢?
不推薦方式一:
思路:先從ObjectContext取出實體,然後將前台傳過來的DTO屬性對應賦值到我們的實體上,然後調用ObjectContext的保證修改方法。
但是這種方式是最不提倡的,因為這樣每次修改前都得先將資料查出來,經過SqlProfiler追蹤,這麼一個操作要對資料庫進行兩次的串連。這是不可忍受的!
推薦方式二:
思路:無需先查出實體,因為我們知道EF通過
ObjectStateManage來控制添加、修改、刪除隊列以及實體的狀態,我們所有可以通過在直接將DTO轉化成實體,然後將實體對應的隊列中,並且我們手動的將實體的狀態處理好,再調用ObjectContext的保證修改方法,這樣就避免了先查詢後修改,兩次資料庫連接的問題了。執行個體代碼如下:
static void Main(string[] args)
{
SchoolDBEntities schoolDB = new SchoolDBEntities();
//假設:網路傳一個StudentDTO過來 ,將此DTO轉化成 資料庫實體
Student student = new Student();
student.Id = 1;// 假設DTO傳過來的值,主鍵必須存在,不然會報錯的
student.Address = "北京上地1";
student.Name = "飛龍1";
student.Phone = "1101";
//先將實體附加到實體上下文中
schoolDB.Student.Attach(student);
//手動修改實體的狀態
schoolDB.ObjectStateManager.ChangeObjectState(student, EntityState.Modified);
//儲存回資料庫
schoolDB.SaveChanges();
}
總算把這塊描述完了!希望對初學者有用!歡迎高手指正錯誤!
技術改變世界,奮鬥改變人生!
Entity
Framework快速入門--索引貼