再接再厉VS 2008 sp1 + .NET 3.5 sp1(5) - Entity Framework(实体框架)之ObjectContext
作者:webabcd
介绍
以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>
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();
}
}
}
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>
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();
}
}
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();
}
}
OK
[源码下载]