之前使用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); //添加前: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方法添加实体的没什么区别。
我们看一个标记实体为未改变实体:
/// <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发送到数据库。
修改:
/// <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知道要更新实体了,但是它并不知道具体更新的是哪一列,所以每一列都更新了。见上面的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.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集合内的[实体]同步.
- ApplyPropertyChanges调用时,要求对应的[实体]在内存中,Attach不要求
- ApplyPropertyChanges调用后,集合内的实体状态会标记为EntityState.ModifiedAttach调用后不会修改合内的实体状态,如要SaveChanges(),要手动标记EntityState.Modified
- 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: DetachedConsole.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几个状态的说明
时间: 2024-10-31 23:35:44