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();
}
}