EF中的EntityState幾個狀態的說明

以前使用EF,咱們都是經過調用SaveChanges方法把增長/修改/刪除的數據提交到數據庫,可是上下文是如何知道實體對象是增長、修改仍是刪除呢?答案是經過EntityState枚舉來判斷的,咱們看一個方法:html

/// <summary>
        /// 查看實體狀態
        /// </summary>
        private static void GetOneEntityToSeeEntityState()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var destination = context.Destinations.Find(4);
                EntityState stateBefore = context.Entry(destination).State;
                Console.WriteLine(stateBefore);
            }
        }

注:使用EntityState需添加引用system.data    
跑下程序,輸出結果爲:Unchanged。從英文意思咱們已經猜到一二:取出來的數據是Unchanged,那麼添加、修改、刪除天然也就是Added、Modified、Deleted了。咱們在EntityState上按F12定位到其定義看看:   sql

  

的確,當調用SaveChanges方法的時候,EF會根據EntityState這個枚舉檢測到實體的狀態,而後執行相應的增/刪/改操做。它們的具體意思分別爲:數據庫

  • Detached:對象存在,但未由對象服務跟蹤。在建立實體以後、但將其添加到對象上下文以前,該實體處於此狀態;
  • Unchanged:自對象加載到上下文中後,或自上次調用 System.Data.Objects.ObjectContext.SaveChanges() 方法後,此對象還沒有通過修改;
  • Added:對象已添加到對象上下文,但還沒有調用 System.Data.Objects.ObjectContext.SaveChanges() 方法;
  • Deleted:使用 System.Data.Objects.ObjectContext.DeleteObject(System.Object) 方法從對象上下文中刪除了對象;
  • Modified:對象已更改,但還沒有調用 System.Data.Objects.ObjectContext.SaveChanges() 方法。

ok,已經知道了這個,咱們利用EntityState這個枚舉修改下以前單個實體的增刪改方法:緩存

增長:服務器

/// <summary>
        /// 添加:DbSet.Add = > EntityState.Added
        /// </summary>
        private static void TestAddDestination()
        {
            var jacksonHole = new DbContexts.Model.Destination
            {
                Name = "Jackson Hole,Wyoming",
                Description = "Get your skis on."
            };
            //AddDestinationByDbSetAdd(jacksonHole);
            AddDestinationByEntityStateAdded(jacksonHole);
        }
        private static void AddDestinationByDbSetAdd(DbContexts.Model.Destination destination)
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                context.Destinations.Add(destination);
                context.SaveChanges();
            }
        }
        private static void AddDestinationByEntityStateAdded(DbContexts.Model.Destination destination)
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                Console.WriteLine(context.Entry(destination).State);    //添加前:Detached
                context.Entry(destination).State = EntityState.Added;
                Console.WriteLine(context.Entry(destination).State);    //添加後:Added
                context.SaveChanges();
            }
        }
exec sp_executesql N'insert [baga].[Locations]([LocationName], [Country], [Description], [Photo], [TravelWarnings], [ClimateInfo])
values (@0, null, @1, null, null, null)
select [LocationID]
from [baga].[Locations]
where @@ROWCOUNT > 0 and [LocationID] = scope_identity()',N'@0 nvarchar(200),@1 nvarchar(500)',@0=N'Jackson Hole,Wyoming',@1=N'Get your skis on.'

監控到的sql也跟以前調用DbSet.Add方法添加實體的沒什麼區別。併發

咱們看一個標記實體爲未改變實體:ide

/// <summary>
        /// 標記一個未改變的實體
        /// </summary>
        private static void TestAttachDestination()
        {
            DbContexts.Model.Destination canyon;
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                canyon = (from d in context.Destinations
                          where d.Name == "Grand Canyon"
                          select d).Single();
            }
            AttachDestination(canyon);
        }
        private static void AttachDestination(DbContexts.Model.Destination destination)
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                Console.WriteLine(context.Entry(destination).State);    //標記前:Detached
                context.Destinations.Attach(destination);  //修改使用Attach方法
                //context.Entry(destination).State = EntityState.Unchanged;   //跟Attach方法同樣效果
                Console.WriteLine(context.Entry(destination).State);    //標記後:Unchanged
                context.SaveChanges();
            }
        }

能夠看出,實體從數據庫取出是Detached狀態,調用Attach方法變成了Unchanged狀態。Unchanged狀態會被SaveChanges方法忽略掉,不會有任何sql發送到數據庫。post

修改:學習

/// <summary>
        /// 修改:EntityState.Modified
        /// </summary>
        private static void TestUpdateDestination()
        {
            DbContexts.Model.Destination canyon;
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                canyon = (from d in context.Destinations
                          where d.Name == "Grand Canyon"
                          select d).Single();
            }
            canyon.TravelWarnings = "Don't Fall in!";
            UpdateDestination(canyon);
        }
        private static void UpdateDestination(DbContexts.Model.Destination destination)
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                Console.WriteLine(context.Entry(destination).State);    //修改前:Detached
                context.Entry(destination).State = EntityState.Modified;
                Console.WriteLine(context.Entry(destination).State);    //修改後:Modified
                context.SaveChanges();
            }
        }
exec sp_executesql N'update [baga].[Locations]
set [LocationName] = @0, [Country] = @1, [Description] = @2, [Photo] = null, [TravelWarnings] = @3, [ClimateInfo] = null
where ([LocationID] = @4)
',N'@0 nvarchar(200),@1 nvarchar(max) ,@2 nvarchar(500),@3 nvarchar(max) ,@4 int',@0=N'Grand Canyon',@1=N'USA',@2=N'One huge canyon.',@3=N'Don''t Fall in!',@4=1

咱們標記實體爲Modified後調用SaveChanges方法後,EF知道要更新實體了,可是它並不知道具體更新的是哪一列,因此每一列都更新了。見上面的sqlthis

刪除:

/// <summary>
        /// 刪除:DbSet.Remove = > EntityState.Deleted
        /// </summary>
        private static void TestDeleteDestination()
        {
            DbContexts.Model.Destination canyon;
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                canyon = (from d in context.Destinations
                          where d.Name == "Grand Canyon"
                          select d).Single();
            }
            //DeleteDestination(canyon);
            DeleteDestinationByEntityStateDeletion(canyon);
        }
        private static void DeleteDestination(DbContexts.Model.Destination destination)
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                context.Destinations.Attach(destination);  //先告訴EF這個實體
                context.Destinations.Remove(destination);  //執行刪除
                context.SaveChanges();
            }
        }
        private static void DeleteDestinationByEntityStateDeletion(DbContexts.Model.Destination destination)
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                Console.WriteLine(context.Entry(destination).State);    //刪除前:Detached
                context.Entry(destination).State = EntityState.Deleted;
                Console.WriteLine(context.Entry(destination).State);    //刪除後:Deleted
                context.SaveChanges();
            }
        }
exec sp_executesql N'delete [baga].[Locations]
where ([LocationID] = @0)',N'@0 int',@0=1
 
 
 
 
 
 
 
 
 
ADO.NET Entity Framework學習筆記(3)ObjectContext對象[轉] 

說明

 

ObjectContext提供了管理數據的功能

 

 

Context操做數據

 

 

AddObject 添加實體

將實體添加到集合中,

建立實體時,狀態爲EntityState.Detached

當調用AddObject將實體添加到Context,狀態爲EntityState.Added

myContext context = new myContext(); 

myTab r = new myTab();

r.ID = 10;

r.a = "wxwinter"

Console.WriteLine(r.EntityState); //print:Detached 

context.AddTomyTab(r); 

Console.WriteLine(r.EntityState); //print:Added 

context.SaveChanges();

myContext context = new myContext(); 

myTab newrow = new myTab() { a = "wxd", b = "lzm", c = "wxwinter" }; 

context.AddObject("myTab",newrow); 

context.SaveChanges();

 

DeleteObject 刪除實體

將集合中的實體添標記爲刪除

當調用Context.DeleteObject,並非將實體移除集合,而是將實體添標記爲EntityState.Deleted ,在下次調用SaveChanges()方法時跟新數據庫

myContext context = new myContext(); 

myTab r = context.myTab.First(p=>p.ID==1); 

Console.WriteLine(r.EntityState); //print:Unchanged 

context.DeleteObject(r); 

Console.WriteLine(r.EntityState); //print:Deleted 

context.SaveChanges();

 

Detach 分離實體

將實體從Context中分離,將狀態標記爲EntityState.Detached 。

myContext context = new myContext(); 

myTab r = myTab.CreatemyTab(22); 

Console.WriteLine(r.EntityState); //print:Detached 

context.AddTomyTab(r); 

Console.WriteLine(r.EntityState); //print:Added 

context.Detach(r); 

Console.WriteLine(r.EntityState); //print: Detached

修改實體

能夠直接修在實體對象上修改

當修改在Context中的實體時,會將實體的狀態標記爲EntityState.Modified

myContext context = new myContext(); 

myTab r = context.myTab.First(p=>p.ID==1);

Console.WriteLine(r.EntityState); //print:Unchanged

r.a = "wxwinter";

Console.WriteLine(r.EntityState); //print:Modified 

context.SaveChanges();

 

ApplyPropertyChanges 修改實體

 

使用ApplyPropertyChanges,可使用不在集合中的實體覆蓋到集合中主鍵對應用實體上,若是內存中沒有主鍵對應的記錄,會報錯:「ObjectStateManager 不包含具備對「XXX」類型的對象的引用的 ObjectStateEntry。」該方法還有一個特色就是,會拿內存中的對象(新對象)和context中的對象(舊對象)對比,自動生成對應字段修改的Update語句,若是內存中的對象與context中的對象徹底相等(每一個字段的值都相等),將不生成響應的Update

myContext context = new myContext();

myTab r1 = context.myTab.First(p => p.ID == 1); 

myTab nr = myTab.CreatemyTab(1);

nr.a = "wxwinter"

Console.WriteLine(nr.EntityState); //print:Detached

Console.WriteLine(r1.EntityState); //print:Unchanged 

context.ApplyPropertyChanges("myTab", nr); 

myTab r2 = context.myTab.First(p => p.ID == 1); 

Console.WriteLine(nr.EntityState); //print:Detached

Console.WriteLine(r2.EntityState); //print:Modified 

context.SaveChanges();

 

Orders order;
using (NorthwindEntities ne = new NorthwindEntities())
{
    
//利用EntityObject.Execute(MergeOption.NoTracking),等效於使用ObjectContext.Dettach(EntityObject)
    
//查詢並分離對象
    order = ne.Orders.Execute(MergeOption.NoTracking).Where(v => v.OrderID == 10248).FirstOrDefault();
}
//修改分離的值
order.ShipName = "1111111111111111";
//使用分離的對象 order 更新 
using (NorthwindEntities context = new NorthwindEntities())
{
    
//將數據載入到context中以便更新
    context.GetObjectByKey(order.EntityKey);
    
//使用order 更新 context中的對應對象
    context.ApplyPropertyChanges(order.EntityKey.EntitySetName, order);
    context.SaveChanges();
}

 

Attach / AttachTo 附加實體

使用Attach方法可將[外部實體]附加到Context集合中

在使用 服務器/客戶端模式,或要將[實體]從Context集合中分離,修改後要用Context更新回數據庫時,可用這種方式

Attach與ApplyPropertyChanges有相似之處,都是將Context集合外的[實體]與Context集合內的[實體]同步.

  1. ApplyPropertyChanges調用時,要求對應的[實體]在內存中,Attach不要求
  2. ApplyPropertyChanges調用後,集合內的實體狀態會標記爲EntityState.Modified
    Attach調用後不會修改合內的實體狀態,如要SaveChanges(),要手動標記EntityState.Modified
  3. ApplyPropertyChanges是用[外部實體]全覆蓋Context集合中的[實體],
    Attach方式,經過SetModifiedProperty()方法,可在調用SaveChanges()時,只修改只定有字段值  

myContext context = new myContext(); 
myTab v 
= myTab.CreatemyTab(1);  
v.EntityKey 
= context.CreateEntityKey("myTab", v); 
v.a 
= "wxwinter";
context.Attach(v);
//context.AttachTo("myTab", v);
ObjectStateEntry ose = context.ObjectStateManager.GetObjectStateEntry(v);
//設置修改
ose.SetModified();
//指定修改的字段名
ose.SetModifiedProperty("a");
context.SaveChanges();

修改前

 

修改後

 

 

CreateEntityKey 建立EntityKey

myContext context = new myContext();

 

myTab nr = myTab.CreatemyTab(1);

 

EntityKey ek= context.CreateEntityKey("myTab", nr);

 

EntityKey

EntityContainerName 屬性

 

EntityKeyValues 集合

 

EntitySetName 屬性

 

IsTemporary 屬性

 

GetEntitySet(System.Data.Metadata.Edm.MetadataWorkspace) 方法

 

OnDeserialized(System.Runtime.Serialization.StreamingContext) 方法

 

OnDeserializing(System.Runtime.Serialization.StreamingContext) 方法

 

 

GetObjectByKey/TryGetObjectByKey 經過EntityKey獲得實體

myContext context = new myContext(); 

myTab nr = myTab.CreatemyTab(1);

EntityKey ek= context.CreateEntityKey("myTab", nr); 

myTab r = context.GetObjectByKey(ek) as myTab

Console.WriteLine("{0},{1},{2},{3}", r.ID, r.a, r.b, r.c);

myContext context = new myContext(); 

myTab nr = myTab.CreatemyTab(1);

EntityKey ek= context.CreateEntityKey("myTab", nr);
object obj;

if (context.TryGetObjectByKey(ek,out obj))

{

    myTab r = obj as myTab;

    Console.WriteLine("{0},{1},{2},{3}", r.ID, r.a, r.b, r.c);

}

 

CreateQuery 建立查詢

更多見esql

myContext context = new myContext(); 

string esql = "SELECT VALUE DBItemList FROM myContext.DBItemList"

// ObjectQuery<DBItemList> query = new ObjectQuery<DBItemList>(esql, context); 

ObjectQuery<DBItemList> query = context.CreateQuery<DBItemList>(esql); 

foreach (DBItemList r in query)

{

    Console.WriteLine(r.NameID);

}

 

 

 

 

狀態管理

 

EntityState 狀態枚舉

EntityState.Added 已經過AddObject方法加到集合中,AcceptChanges 還沒有調用。

EntityState.Deleted 已經過 DeleteObject 方法被刪除。

EntityState.Detached 已被建立,但不屬於任何集合。在如下狀況下當即處於此狀態:建立以後添加到集合中以前;或從集合中移除以後。

EntityState.Modified 已被修改,AcceptChanges 還沒有調用。

EntityState.Unchanged 自上次調用 AcceptChanges 以來還沒有更改

 

Context.ObjectStateManager 管理記錄的狀態

GetObjectStateEntry 根據實體對象或實體主鍵獲得狀態實體

實體必須在當前鏈接對象 context 中不然沒法獲取實體狀態會引起:
ObjectStateManager 不包含具備對「 context 」類型的對象的引用的 ObjectStateEntry
也就是該方法沒法獲取已分離的實體對象狀態

ObjectStateEntry = GetObjectStateEntry(實體對像/EntityKey

獲得所指定的[實體對像]EntityKey ObjectStateEntry

myContext context = new myContext();

myTab r = myTab.CreatemyTab(22);

context.AddTomyTab(r);

 

// ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

ObjectStateEntry ose = context.ObjectStateManager.GetObjectStateEntry(r.EntityKey);

 

Console.WriteLine(ose.State); //print:Added

 

TryGetObjectStateEntry 根據實體對象或實體主鍵獲得狀態實體

bool = TryGetObjectStateEntry(實體對像/EntityKey,out ObjectStateEntry)

 

獲得所指定的[實體對像]EntityKey ObjectStateEntry

myContext context = new myContext();

myTab r = myTab.CreatemyTab(22); 

context.AddTomyTab(r); 

ObjectStateEntry ose; 

if( context.ObjectStateManager.TryGetObjectStateEntry(r,out ose))

{

    Console.WriteLine(ose.State); //print:Added

}

 

GetObjectStateEntries 根據狀態類型獲得狀態實體集合

IEnumerable<ObjectStateEntry> = GetObjectStateEntries(EntityState枚舉

返回IEnumerable<ObjectStateEntry>,獲得EntityState枚舉所指定的某種狀態的列表

myContext context = new myContext(); 

myTab r = myTab.CreatemyTab(22); 

context.AddTomyTab(r);

IEnumerable<ObjectStateEntry> oseList = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added);

foreach (ObjectStateEntry v in oseList)

{

    Console.WriteLine("{0},{1},{2}", v.State, v.CurrentValues["ID"], v.EntitySet.Name);

}

//print:Added,22,myTab

 

ObjectStateManagerChanged 事件

CollectionChangeEventHandler(object sender, CollectionChangeEventArgs e)

e.Action : 集合操做行爲

System.ComponentModel.CollectionChangeAction.Add

System.ComponentModel.CollectionChangeAction.Refresh

System.ComponentModel.CollectionChangeAction.Remove 

e.Element : 操做的實體對象

 

void ObjectStateManager_ObjectStateManagerChanged(object sender, CollectionChangeEventArgs e)

    Console.WriteLine(e.Action);
    myTab v = e.Element as myTab;

    Console.WriteLine("{0}",v.ID);

}

//===================================

myContext context = new myContext();

context.ObjectStateManager.ObjectStateManagerChanged+=new CollectionChangeEventHandler(ObjectStateManager_ObjectStateManagerChanged);

myTab r = myTab.CreatemyTab(22);

context.AddTomyTab(r);

/*

*print:

Add

22

*/

 

ObjectStateEntry 對象

基本屬性

IsRelationship 屬性

 

Entity 屬性

 

EntityKey 屬性

 

EntitySet 屬性

 

 

 

State 狀態屬性

EntityState 枚舉

myContext context = new myContext();

myTab r = myTab.CreatemyTab(22);

context.AddTomyTab(r);

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

Console.WriteLine(ose.State); //print:Added

 

CurrentValues 當前值

處於 deleted detached 狀態的對象沒有當前值。

myContext context = new myContext();

myTab r = new myTab() { ID = 22, a = "wxwinter" };

context.AddTomyTab(r);

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

Console.WriteLine("{0},{1}",ose.CurrentValues["ID"],ose.CurrentValues["a"]);

//print: 22,wxwinter

 

OriginalValues 原始值

處於 added detached 狀態的對象沒有原始值

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);

 

r.a = "wxwinter";

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

 

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

/*

* print:

Modified

CurrentValues :1,wxwinter

OriginalValues:1,aa

*/

 

 

GetModifiedProperties 獲得被修改的屬性

返回IEnumerable<string>

 

獲得被修改的屬性集合

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);

 

r.a = "wxwinter";

r.b = "wxd";

 

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

IEnumerable<string> list = ose.GetModifiedProperties();

foreach (string pr in list)

{

Console.WriteLine(pr);

}

/*

* print:

a

b

*/

 

SetModified,SetModifiedProperty 標記爲修改

SetModified() 方法將記錄標記爲 EntityState.Modified

只是這樣,調用Context.SaveChanges方法是沒法保存修改到數據庫中的,Context.SaveChanges方法要查找被修改過的屬性,

可用SetModifiedProperty方法標記被修改過的屬性

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);

r.a = "wxwinter"

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);
ose.AcceptChanges();

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

/*

* print:

Unchanged

CurrentValues :1,wxwinter

OriginalValues:1,wxwinter

*/

 

ose.SetModified();

ose.SetModifiedProperty("a");

 

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

 

/*

* print:

Modified

CurrentValues :1,wxwinter

OriginalValues:1,wxwinter

*/

context.SaveChanges();

 

Delete 標記爲刪除

標記爲EntityState.Deleted

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

ose.Delete();

Console.WriteLine(ose.State); //print: Detached

 

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

//print:OriginalValues:1,wxwinter

用 context.DeleteObject方法的效果與上例同樣

 

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);
ObjectStateEntry ose = context.ObjectStateManager.GetObjectStateEntry(r);
context.DeleteObject(r);
Console.WriteLine(ose.State); //print: Detached
Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

//print:OriginalValues:1,wxwinter

 

AcceptChanges 方法

將記錄的狀態置爲EntityState.Unchanged

[CurrentValues 當前值]替換[OriginalValues 原始值],

使用[ Context.AcceptAllChanges 方法]也有一樣效果

注意:狀態爲[EntityState.Deleted ]的記錄,會被[Detach]

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);
r.a = "wxwinter";

context.AcceptAllChanges();
ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

ose.AcceptChanges();

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

/*

* print:

Unchanged

CurrentValues :1,wxwinter

OriginalValues:1,wxwinter

*/

當調用AcceptChanges時,若是對像處於[EntityState.Deleted ],會將對象移除集合,這時對像的狀態爲[EntityState.Detached ]

 

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

ose.Delete();

ose.AcceptChanges();

Console.WriteLine(ose.State); //print: Detached

 

 

 

保存修改到數據庫

 

Context.SaveChanges 方法

若是集合中有狀態爲EntityState.Added的記錄,用[CurrentValues 當前值]添加到數據庫中

 

若是集合中有狀態爲EntityState.Deleted的記錄,從數據庫是刪除與之對應的數據庫記錄

 

若是集合中有狀態爲EntityState.Modified的記錄,用[OriginalValues 原始值]與對應的數據庫記錄比效,查看併發, 用[CurrentValues 當前值]更新與之對應的數據庫記錄

 

 

SaveChanges(true)

將數據保存到數據庫後

將全部記錄狀態標記爲EntityState.Unchanged ,(調用Context.AcceptAllChanges )

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1); 

r.a = "wxwinter";

ObjectStateEntry ose = context.ObjectStateManager.GetObjectStateEntry(r);

context.SaveChanges(true); 

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

 

/*

* print:

Unchanged

CurrentValues :1,wxwinter

OriginalValues:1,wxwinter

*/

SaveChanges()

SaveChanges(true)相同

SaveChanges(false)

將數據保存到數據庫,

但並不改變記錄狀態

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1); 

r.a = "wxwinter";

ObjectStateEntry ose = context.ObjectStateManager.GetObjectStateEntry(r);

context.SaveChanges(false);

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

 

/*

* print:

Modified

CurrentValues :1,wxwinter

OriginalValues:1,aa

*/

 

Context.SavingChanges 事件

myContext context = new myContext();

context.SavingChanges+=new EventHandler(context_SavingChanges);

myTab r = context.myTab.First(p => p.ID == 1);
r.a = "wxwinter";
context.SaveChanges();

void context_SavingChanges(object sender, EventArgs e)

{

    myContext context = sender as myContext;

    Console.WriteLine(context.DefaultContainerName);

}

 

Context.AcceptAllChanges 方法

將全部記錄的狀態置爲EntityState.Unchanged

[CurrentValues 當前值]替換[OriginalValues 原始值]

效果與對所在記錄的ObjectStateEntry上調用AcceptAllChanges同樣

注意:狀態爲[EntityState.Deleted ]的記錄,會被[Detach]

myContext context = new myContext();

myTab r = context.myTab.First(p => p.ID == 1);

 

r.a = "wxwinter";

context.AcceptAllChanges();

 

ObjectStateEntry ose= context.ObjectStateManager.GetObjectStateEntry(r);

Console.WriteLine(ose.State);

Console.WriteLine("CurrentValues :{0},{1}", ose.CurrentValues["ID"], ose.CurrentValues["a"]);

Console.WriteLine("OriginalValues:{0},{1}", ose.OriginalValues["ID"], ose.OriginalValues["a"]);

/*

* print:

Unchanged

CurrentValues :1,wxwinter

OriginalValues:1,wxwinter

*/

 

 

 

 

鏈接屬性

 

Context.DefaultContainerName 屬性

 

Context.Connection 屬性

 

Context.CommandTimeout 屬性

 

 

 

Context.MetadataWorkspace

 

 

 

數據刷新與併發

 

EF提供了兩種併發衝突處理方式:聽任無論方式和開放式併發。默認採用聽任無論的方式處理。

若是要使用開放式併發,必須設置相應屬性上的[併發模式]值[Fixed]

 

後修改數據的ObjectContext緩存了舊版本的數據時,當提交修改後系統就會拋出"OptimisticConcurrencyException"(開放式併發異常)。

當程序捕獲到異常之後,可使用ObjectContext的Refresh方法對異常採起處理。

 

 

 

 

緩存數據不會自動更新

公共

myContext context1 = new myContext();

myContext context2 = new myContext();

查詢

foreach (var r in context1.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

 

Console.WriteLine("---------------------");

 

foreach (var r in context2.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

a,this is a

b,this is b

c,this is c

---------------------

a,this is a

b,this is b

c,this is c

修改

DBItem dbitem1 = context1.DBItem.First(p => p.ItemID == "a");

dbitem1.ItemMatter = "hello";

context1.SaveChanges();

再查詢

foreach (var r in context1.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

 

Console.WriteLine("---------------------");

 

foreach (var r in context2.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

a,hello

b,this is b

c,this is c

---------------------

a,this is a

b,this is b

c,this is c

 

[併發模式]值爲[Fixed]的併發異常

注意,只有後修改數據的ObjectContext緩存了舊版本的數據時,長會產生異常

DBItem dbitem1 = context1.DBItem.First(p => p.ItemID == "a");

dbitem1.ItemMatter = "hello";

context1.SaveChanges();

 

DBItem dbitem2 = context2.DBItem.First(p => p.ItemID == "a");

dbitem2.ItemMatter = "wxwinter";

context2.SaveChanges();

 

ObjectContext.Refresh()

Refresh的第一個參數RefreshMode枚舉,RefreshMode.StoreWins,RefreshMode.ClientWins

StoreWins

StoreWins : Refresh之後,用數據庫的值回寫,當前的修改值被放棄

公共

myContext context1 = new myContext();

myContext context2 = new myContext();

查詢

foreach (var r in context1.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

 

Console.WriteLine("---------------------");

 

foreach (var r in context2.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

a,this is a

b,this is b

c,this is c

---------------------

a,this is a

b,this is b

c,this is c

修改

DBItem dbitem1 = context1.DBItem.First(p => p.ItemID == "a");

dbitem1.ItemMatter = "hello";

context1.SaveChanges();

 

 

DBItem dbitem2 = context2.DBItem.First(p => p.ItemID == "a");

 

dbitem2.ItemMatter = "wxwinter";

try

{

context2.SaveChanges();

}

catch

{

context2.Refresh( RefreshMode.StoreWins , dbitem2);

}

在System.Data.OptimisticConcurrencyException 中第一次偶然出現的"System.Data.Entity.dll"類型的異常

再查詢

foreach (var r in context1.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

 

Console.WriteLine("---------------------");

 

foreach (var r in context2.DBItem)

{

Console.WriteLine("{0},{1}", r.ItemID, r.ItemMatter);

}

a,hello

b,this is b

c,this is c

---------------------

a,hello

b,this is b

c,this is c

 

ClientWins

StoreWins: Refresh之後,當前的修改值仍存在,只是告訴ObjectContext知到的併發問題了,這時再調用 ObjectContext.SaveChanges()時,ObjectContext就不會報[開放式併發異常]

 

DBItem dbitem1 = context1.DBItem.First(p => p.ItemID == "a");

dbitem1.ItemMatter = "hello";

context1.SaveChanges(); 

DBItem dbitem2 = context2.DBItem.First(p => p.ItemID == "a"); 

dbitem2.ItemMatter = "wxwinter";

try

{

context2.SaveChanges();

}

catch

{

context2.Refresh(RefreshMode.ClientWins, dbitem2);

context2.SaveChanges();

}

 

也能夠先Refresh()再SaveChanges(),而不用異常捕獲

DBItem dbitem1 = context1.DBItem.First(p => p.ItemID == "a");

dbitem1.ItemMatter = "hello";

context1.SaveChanges(); 

DBItem dbitem2 = context2.DBItem.First(p => p.ItemID == "a"); 

dbitem2.ItemMatter = "wxwinter"

context2.Refresh(RefreshMode.ClientWins, dbitem2);

context2.SaveChanges();

 

 

事務處理

 

同一SubmitChanges 會作默認的事務處理

下例因爲ItemID主鍵衝突,兩條數據都不會被插入

myContext context1 = new myContext();

DBItem item1 = new DBItem();

item1.ItemID = "w";

item1.ItemMatter = "wxwinter";

context1.AddObject("DBItem", item1); 

DBItem item2 = new DBItem();

item2.ItemID = "w";

item2.ItemMatter = "wxd";

context1.AddObject("DBItem", item2); 

context1.SaveChanges();

 

不一樣SubmitChanges 不會作事務處理

下例因爲ItemID主鍵衝突,後一條數據都不會被插入

 

myContext context1 = new myContext();

DBItem item1 = new DBItem();

item1.ItemID = "w";

item1.ItemMatter = "wxwinter";

context1.AddObject("DBItem", item1);

context1.SaveChanges();

 

myContext context2 = new myContext();

DBItem item2 = new DBItem();

item2.ItemID = "w";

item2.ItemMatter = "wxd";

context2.AddObject("DBItem", item2);

context2.SaveChanges();

 

System.Data.Common.DbTransaction

下例因爲ItemID主鍵衝突,兩條數據都不會被插入

 

myContext context1 = new myContext();

DBItem item1 = new DBItem();

item1.ItemID = "w";

item1.ItemMatter = "wxwinter";

context1.AddObject("DBItem", item1);

 

if (context1.Connection.State != ConnectionState.Open)

{

context1.Connection.Open();

}

System.Data.Common.DbTransaction tran = context1.Connection.BeginTransaction();

context1.SaveChanges();

 

try

{

 

DBItem item2 = new DBItem();

item2.ItemID = "w";

item2.ItemMatter = "wxd";

context1.AddObject("DBItem", item2);

context1.SaveChanges();

tran.Commit();

}

catch

{

tran.Rollback();

}

 

死鎖(兩個Context使用DbTransaction)

 

myContext context1 = new myContext();

DBItem item1 = new DBItem();

item1.ItemID = "w";

item1.ItemMatter = "wxwinter";

context1.AddObject("DBItem", item1);

 

if (context1.Connection.State != ConnectionState.Open)

{

context1.Connection.Open();

}

System.Data.Common.DbTransaction tran = context1.Connection.BeginTransaction();

context1.SaveChanges();

 

try

{

myContext context2 = new myContext();

DBItem item2 = new DBItem();

item2.ItemID = "w";

item2.ItemMatter = "wxd";

context2.AddObject("DBItem", item2);

context2.SaveChanges();

tran.Commit();

}

catch

{

tran.Rollback();

}

 

TransactionScope 事務(兩個Context)

System.Transactions.TransactionScope

可解決[死鎖(兩個Context使用DbTransaction)]

下例因爲ItemID主鍵衝突,兩條數據都不會被插入

using (System.Transactions.TransactionScope tc = new TransactionScope())

{

 

try

{

 

myContext context1 = new myContext();

DBItem item1 = new DBItem();

item1.ItemID = "w";

item1.ItemMatter = "wxwinter";

context1.AddObject("DBItem", item1);

context1.SaveChanges();

 

myContext context2 = new myContext();

DBItem item2 = new DBItem();

item2.ItemID = "w";

item2.ItemMatter = "wxd";

context2.AddObject("DBItem", item2);

context2.SaveChanges();

tc.Complete();

}

catch

{

}

}

相關文章
相關標籤/搜索