Entity Framework(實體框架)之ObjectContext
介紹
以Northwind為示例數據庫,ADO.NET Entity Framework之詳解ObjectContext, 以及事務和並發
ObjectContext - 以對象(這些對象是 EDM 中定義的實體類型的實例)的形式與數據進行交互
CreateObjectName - 實體類 的 CreateObjectName 靜態方法用於創建實體類的新實例
AddToEntitySetName() - 將需要添加的對象添加到對象上下文中
SaveChanges() - 將所有更新保存到相關存儲區中
Attach()/AttachTo() - 附加外部實體到上下文中
ObjectContext.Refresh() - 更新上下文數據
ObjectStateEntry - 維護實體狀態的類
ObjectStateManager - 實體狀態管理器
示例
1、詳解ObjectContext
ObjectContext.aspx
<%@ Page Title="ObjectContext" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="ObjectContext.aspx.cs" Inherits="EntityFramework_ObjectContext" %> <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server"> <div id="result" runat="server" /> </asp:Content>
ObjectContext.aspx.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data.Objects; using System.Data.Objects.DataClasses; using System.Data; using VS2008SP1.Business; public partial class EntityFramework_ObjectContext : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { Demo(); result.InnerHtml += "<br />"; Demo2(); result.InnerHtml += "<br />"; Demo3(); result.InnerHtml += "<br />"; Demo4(); result.InnerHtml += "<br />"; Demo5(); result.InnerHtml += "<br />"; Demo6(); } } private void Demo() { // ObjectContext - 以對象(這些對象是 EDM 中定義的實體類型的實例)的形式與數據進行 交互 using (var ctx = new NorthwindEntities()) { // CreateObjectName - 實體類 的 CreateObjectName 靜態方法用於創建實體類的新實例 Region region = Region.CreateRegion("RegionDescription", 100); // System.Data.EntityState - 實體狀態 // System.Data.EntityState.Detached - 被分離 // System.Data.EntityState.Unchanged - 未發生變化 // System.Data.EntityState.Added - 被增加 // System.Data.EntityState.Deleted - 被刪除 // System.Data.EntityState.Modified - 被修改 result.InnerHtml += region.EntityState + "<br />"; // Detached // AddToEntitySetName() - 將需要添加的對象添加到對象上下文中 // AddObject(string entitySetName, object entity) - 將需要添加的對象添加到對象上 下文中 // ctx.AddObject("Region", region); ctx.AddToRegion(region); result.InnerHtml += region.EntityState + "<br />"; // Added // SaveChanges() - 將所有更新保存到相關存儲區中。將所有實體的 EntityState 標記為 EntityState.Unchanged // SaveChanges(bool acceptChangesDuringSave) - acceptChangesDuringSave 指定是否 將所有實體的 EntityState 標記為 EntityState.Unchanged 。 如果指定為 false 則不會修改實體的 EntityState ctx.SaveChanges(); result.InnerHtml += region.EntityState + "<br />"; // Unchanged } } private void Demo2() { using (var ctx = new NorthwindEntities()) { Region region = ctx.Region.First(p => p.RegionID == 100); result.InnerHtml += region.EntityState + "<br />"; // Unchanged region.RegionDescription = "RegionDescriptionUpdated"; result.InnerHtml += region.EntityState + "<br />"; // Modified ctx.SaveChanges(false); // ObjectStateEntry - 維護實體狀態的類 // GetModifiedProperties() - 獲取被修改的屬性。返回值 IEnumerable<string> // ObjectStateManager - 實體狀態管理器 // GetObjectStateEntry()/TryGetObjectStateEntry() - 獲取指定實體的 ObjectStateEntry // GetObjectStateEntries(EntityState state) - 獲取所指定狀態的 ObjectStateEntry 集合。返回值 IEnumerable<ObjectStateEntry> // ObjectStateManagerChanged事件 - 將實體添加到 ObjectStateManager 中或從中 移除實體時發生 ObjectStateEntry ose = ctx.ObjectStateManager.GetObjectStateEntry(region); // ObjectStateEntry.State - 實體狀態 // ObjectStateEntry.OriginalValues - 原始值 // ObjectStateEntry.CurrentValues - 當前值 result.InnerHtml += ose.State + "<br />"; // Modified (region.EntityState) result.InnerHtml += ose.OriginalValues["RegionDescription"] + "<br />"; // RegionDescription result.InnerHtml += ose.CurrentValues["RegionDescription"] + "<br />"; // RegionDescriptionUpdated // ObjectStateEntry.AcceptChanges()/ObjectContext.AcceptAllChanges() - 將相關的 實體狀態置為 EntityState.Unchanged ose.AcceptChanges(); result.InnerHtml += ose.State + "<br />"; // Unchanged } } private void Demo3() { using (var ctx = new NorthwindEntities()) { // 加載指定的 Region 到上下文中 Region regionRead = ctx.Region.First(p => p.RegionID == 100); // 創建一個需要更新的 Region Region regionUpdate = Region.CreateRegion("RegionDescriptionUpdatedSecond", 100); result.InnerHtml += regionRead.EntityState + "<br />"; // Unchanged result.InnerHtml += regionUpdate.EntityState + "<br />"; // Detached // ApplyPropertyChanges(string entitySetName, object changed) - 更新指定的實體( 其所對應的主鍵實體需要加載到上下文中) ctx.ApplyPropertyChanges("Region", regionUpdate); result.InnerHtml += regionRead.EntityState + "<br />"; // Modified result.InnerHtml += regionUpdate.EntityState + "<br />"; // Detached ctx.SaveChanges(); } } private void Demo4() { using (var ctx = new NorthwindEntities()) { Region region = new Region() { RegionID = 100, RegionDescription = "RegionDescriptionUpdatedThird" }; result.InnerHtml += region.EntityState + "<br />"; // Detached // Attach()/AttachTo() - 附加外部實體到上下文中 // ctx.Attach(region); ctx.AttachTo("Region", region); ObjectStateEntry ose = ctx.ObjectStateManager.GetObjectStateEntry(region); // SetModified() - 標記實體狀態為 EntityState.Modified // SetModifiedProperty() - 標記需要修改的屬性,從而完成對指定屬性的修改 ose.SetModifiedProperty("RegionDescription"); // 以當前數據為准更新存儲模型 ctx.Refresh(RefreshMode.ClientWins, region); result.InnerHtml += region.EntityState + "<br />"; // Modified ctx.SaveChanges(); } } private void Demo5() { using (var ctx = new NorthwindEntities()) { Region region = new Region() { RegionID = 100 }; // CreateEntityKey(string entitySetName, object entity) - 創建 EntityKey EntityKey ek = ctx.CreateEntityKey("Region", region); // ObjectContext.GetObjectByKey()/TryGetObjectByKey() - 根據指定的 EntityKey 獲 取實體 Region r = ctx.GetObjectByKey(ek) as Region; ctx.SaveChanges(); result.InnerHtml += r.RegionDescription + "<br />"; // RegionDescriptionUpdatedThird } } private void Demo6() { using (var ctx = new NorthwindEntities()) { Region region = ctx.Region.First(p => p.RegionID == 100); result.InnerHtml += region.EntityState + "<br />"; // Unchanged // ObjectStateEntry.Delete() - 標記實體的狀態為刪除。同 DeleteObject() ObjectStateEntry ose = ctx.ObjectStateManager.GetObjectStateEntry(region); ose.Delete(); // DeleteObject() - 刪除實體 // ctx.DeleteObject(region); result.InnerHtml += region.EntityState + "<br />"; // Deleted ctx.SaveChanges(); } } }
2、事務和並發處理
ObjectContext2.aspx
<%@ Page Title="事務和並發處理" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="ObjectContext2.aspx.cs" Inherits="EntityFramework_ObjectContext2" %> <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server"> <div id="result" runat="server" /> </asp:Content>
ObjectContext2.aspx.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data.Objects; using System.Data.Objects.DataClasses; using System.Data; using VS2008SP1.Business; public partial class EntityFramework_ObjectContext2 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { // 演示事務的 Demo Demo(); result.InnerHtml += "<br />"; // 演示並發的 Demo Demo2(); } } private void Demo() { // ObjectContext - SaveChanges 中的邏輯會自動做事務處理 // 通吃的事務處理 // using (System.Transactions.TransactionScope tc = new TransactionScope()) // { // code // tc.Complete(); // } // 同一 ObjectContext 的多個 SaveChanges() 的事務處理 using (var ctx = new NorthwindEntities()) { Region region = Region.CreateRegion("Test", 101); ctx.AddToRegion(region); if (ctx.Connection.State != ConnectionState.Open) { ctx.Connection.Open(); } // 開始一個事務 System.Data.Common.DbTransaction tran = ctx.Connection.BeginTransaction(); // 第一次對數據的操作 ctx.SaveChanges(); try { Region region2 = Region.CreateRegion("Test2", 101); ctx.AddToRegion(region2); // 第二次對數據庫的操作 ctx.SaveChanges(); // 提交事務(第一次插入主鍵為 101 的記錄,成功;第二次再次插入主鍵為 101 的 記錄,失敗。所以此處會報錯) tran.Commit(); } catch (Exception) { result.InnerHtml += "回滾" + "<br />"; // 回滾事務(第一次插入成功的主鍵為 101 的記錄會被刪除) tran.Rollback(); } } } private void Demo2() { var ctx = new NorthwindEntities(); var ctx2 = new NorthwindEntities(); var region = ctx.Region.First(); var region2 = ctx2.Region.First(); // 需要做並發處理的字段,要將其“並發模式”屬性設置為 Fixed region.RegionDescription = "Eastern" + Guid.NewGuid().ToString(); region2.RegionDescription = "Eastern" + Guid.NewGuid().ToString(); ctx.SaveChanges(); try { // ctx 已經修改了 Region 的 RegionDescription 屬性 // ctx2 再次修改 Region 的 RegionDescription 屬性,由於 RegionDescription 在 ctx2 讀取之後發生了變化,所以會出現樂觀並發(Optimistic Concurrency)問題 ctx2.SaveChanges(); } catch (System.Data.OptimisticConcurrencyException) { result.InnerHtml += "OptimisticConcurrencyException" + "<br />"; // ObjectContext.Refresh(RefreshMode refreshMode, object entity) - 更新上下文數 據 // RefreshMode.StoreWins - 以數據庫中的值為准 // RefreshMode.ClientWins - 以當前數據為准 // object entity - 需要刷新上下文數據的實體 ctx2.Refresh(RefreshMode.StoreWins, region2); // ctx2.Refresh(RefreshMode.ClientWins, region2); ctx2.SaveChanges(); } // 可以不通過 try catch 處理並發,而是通過 Refresh() 直接處理更新邏輯 // 即若是 RefreshMode.ClientWins 則永遠以當前值為准;若是 RefreshMode.StoreWins 則永 遠以數據庫中的值為准(不會更新數據) // ctx2.Refresh(RefreshMode.StoreWins, region2); // ctx2.SaveChanges(); ctx.Dispose(); ctx2.Dispose(); } }