之前使用EF,我们都是通过调用SaveChanges方法把增加/修改/删除的数据提交到数据库,但是上下文是如何知道实体对象是增加、修改还是删除呢?答案是通过EntityState枚举来判断的,我们看一个方法:

/// <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定位到其定义看看:

的确,当调用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);    //添加前:Detachedcontext.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方法添加实体的没什么区别。

我们看一个标记实体为未改变实体:

/// <summary>/// 标记一个未改变的实体/// </summary>private static void TestAttachDestination(){DbContexts.Model.Destination canyon;using (var context = new DbContexts.DataAccess.BreakAwayContext()){canyon = (from d in context.Destinationswhere 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);    //标记前:Detachedcontext.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发送到数据库。

修改:

/// <summary>/// 修改:EntityState.Modified/// </summary>private static void TestUpdateDestination(){DbContexts.Model.Destination canyon;using (var context = new DbContexts.DataAccess.BreakAwayContext()){canyon = (from d in context.Destinationswhere 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);    //修改前:Detachedcontext.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知道要更新实体了,但是它并不知道具体更新的是哪一列,所以每一列都更新了。见上面的sql

删除:

/// <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.Destinationswhere 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);    //删除前:Detachedcontext.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

{

}

}

EF中的EntityState几个状态的说明相关推荐

  1. EF中的上下文(DbContext)简介

    EF中的上下文(DbContext)简介 DbContext是实体类和数据库之间的桥梁, DbContext主要负责与数据交互,主要作用: 1.DbContext包含所有的实体映射到数据库表的实体集( ...

  2. ef 执行mysql语句_在EF中执行SQL语句

    一.为什么要在EF中执行SQL语句 使用EF操作数据库,可以避免写SQL语句,完成使用Linq实现,但为什么还要在EF中执行SQL语句呢.如果要写SQL语句,完全可以使用ADO.NET来操作数据库.这 ...

  3. 在EF中执行SQL语句

    一.为什么要在EF中执行SQL语句   使用EF操作数据库,可以避免写SQL语句,完成使用Linq实现,但为什么还要在EF中执行SQL语句呢.如果要写SQL语句,完全可以使用ADO.NET来操作数据库 ...

  4. EF中的那些批量操作

    在使用EF的过程中,我们经常会遇到需要批量操作数据的场景,批量操作有的时候不仅能提高性能,比如使用SqlBulkCopy进入批量插入的时候,而且比较方便操作,提高效率.那么这篇文章就来总结EF中的那些 ...

  5. [转载]EF中的那些批量操作

    阅读目录 插入 更新 删除 在使用EF的过程中,我们经常会遇到需要批量操作数据的场景,批量操作有的时候不仅能提高性能,比如使用SqlBulkCopy进入批量插入的时候,而且比较方便操作,提高效率.那么 ...

  6. EF框架学习(5)---EF中的在线和离线场景

    EF中的持久性场景 使用EF实现实体持久化(保存)到数据库有两种情况:在线场景和离线场景. 1.在线场景 在线场景中,context是同一个上下文实例(从DbContext派生),检索和保存实体都通过 ...

  7. 关于EF中ApplyCurrentValues和ApplyOriginalValues区别

    关于EF中ApplyCurrentValues和ApplyOriginalValues区别:两者都是编辑数据时使用. //         // 摘要:         //     将 System ...

  8. html中radio、checkbox选中状态研究(静下心来看,静下心来总结)

    html中radio.checkbox选中状态研究(静下心来看,静下心来总结) 一.总结 1.单选框的如果有多个checked 会以最后一个为准 2.js动态添加checked属性:不行:通过 $(& ...

  9. Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解...

    2019独角兽企业重金招聘Python工程师标准>>> 今天继续给大家分享下View的相关知识,重点有一下两点:   1.View的几种不同状态属性            2.如何根 ...

最新文章

  1. 解析#pragma指令
  2. Salesforce Service Cloud 十大功能亮点
  3. Delphi 与 DirectX 之 DelphiX(72): TDIB.SephiaEffect();
  4. Android编译笔记二
  5. 2021年中国在线旅游行业分析报告
  6. 图片横向滚动,两边有按钮控制
  7. 视觉里程计02 基于特征匹配的位姿估计
  8. 无法更新标识列 wechatid_天津塘沽企业标识标牌设计制作安装的过程
  9. Origin8.1完全安装教程,安装包pojie包
  10. 基于matlab的gmsk,基于matlab的GMSK综合实训
  11. 30岁开始学编程晚吗?
  12. Starbound服务器信息,《星界边境(starbound)》攻略心得大全 控制台命令一览
  13. Mycat 读写分离、主从切换、分库分表的操作记录
  14. 《C++ STL编程实战》读书笔记(四)
  15. Android Telephony框架结构简析
  16. 五分钟学Java:可变参数究竟是怎么一回事?
  17. Java基础 DAY15
  18. 【Bug】steam双方都是国区 礼物无法入库问题
  19. 小程序 input首行缩进失效
  20. Java中的两种测试方法(JUnit,dbUnit)使用

热门文章

  1. 暑期实训心得及总结_史国旭
  2. 如果获取token?
  3. 快速使用Vitamio框架播放网络视频
  4. 数据存储需求多样化加剧,分而治之成大势所趋
  5. python中累加函数_对Python实现累加函数的方法详解
  6. python+图书管理系统
  7. 多项式 商环 域(群论笔记)
  8. python opencv 直方图均衡_OpenCV-Python教程(10、直方图均衡化)
  9. 电脑族应该怎么保护眼睛
  10. k8spod控制器概述