再接再厉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 on 2010-04-20 17:39  l1b2q31  阅读(289)  评论(0编辑  收藏  举报

导航