再接再厉VS 2008 sp1 + .NET 3.5 sp1(5) - Entity Framework(实体框架)之ObjectContext

[索引页]
[源码下载]


再接再厉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>

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

}


OK
[源码下载]
posted @ 2009-02-09 08:58  webabcd  阅读(6162)  评论(8编辑  收藏  举报