EF中的EntityState几个状态的说明

之前使用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集合内的[实体]同步.
  1. ApplyPropertyChanges调用时,要求对应的[实体]在内存中,Attach不要求
  2. ApplyPropertyChanges调用后,集合内的实体状态会标记为EntityState.ModifiedAttach调用后不会修改合内的实体状态,如要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: 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

EF中的EntityState几个状态的说明的相关文章

EF中的EntityState状态解读

该状态对应的值为以下五种: Detached:对象存在,但未由对象服务跟踪.在创建实体之后.但将其添加到对象上下文之前,该实体处于此状态:Unchanged:自对象加载到上下文中后,或自上次调用 System.Data.Objects.ObjectContext.SaveChanges() 方法后,此对象尚未经过修改:Added:对象已添加到对象上下文,但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法:Deleted:使用 Syst

EF中的增删改查

在上一篇中简单的介绍了一下有关EF的一些概念,都是小编的一些个人理解,懂的不多,想深入学习的可以从网上查看一些其他资料. 下面紧接着上一篇所说,来从代码上看一下EF容器是如何实现与后台数据库之间的增删改查的. 1.EF包装类 什么是EF包装类呢?举个例子,我们平时用SQL语句写增删改查时,用的都是一些Insert.Update.Delete等语句来实现增删改查,所以我们把放到EF容器的东东也要做一个标签,来指明这个东东是要添加.更新.还是要删除呢. 正如上图所示就是这么简单的操作,就完成了对数据

1.Relationship in Entity Framework Using Code First Approach With Fluent API【使用EF Code-First方式和Fluent API来探讨EF中的关系】

In this article, you will learn about relationships in Entity Framework using the Code First Approach with Fluent API. 在这篇文章中,你将会学习到使用EF Code-First方式和Fluent API来探讨EF中的关系(一对一,一对多,多对多). Introduction[介绍] A relationship, in the context of databases, is a

EF 学习系列三 数据操作数据加载及EF中执行Sql

我们通过EF来对数据库进行操作并持久化到数据库,那么EF必然通过EF上下文来维护实体的状态,明确知道每一个状态所对应的操作.也就是说EF通过上下文负责跟踪实体的状态.EF实体状态存在命名空间System.Data.Entity下的EntityState枚举中 原文地址:https://www.cnblogs.com/jhgfdm/p/12274286.html

EF中执行sql语句

EF原理 EF 会自动把 Where().OrderBy().Select()等这些编译成"表达式树(Expression Tree)",然后会把表达式树翻译成 SQL 语句去执行.(编译原理,AST)因此不是"把数据都取到内存中,然后使用集合的方法进行数据过滤",因此性能不会低.但是如果这个操作不能被翻译成 SQL 语句,则或者报错,或者被放到内存中操作,性能就会非常低 跟踪EF的查询Sql语句: DbContext 有一个 Database 属性,其中的 Log

EF中逆变和协变

EF中的增删改查: 实现步骤: 1.声明一个EF的上下文. bjhksjEntities dbContext = new bjhksjEntities(); 2.声明一个实体. HKSJ_USERS user = new HKSJ_USERS(); user.LoginName = "ssss"; user.Mail = "ssss"; user.PassWord = "ssss"; user.Plane = "ssss";

EF中执行原生sql与使用Local获取本地数据

使用DbSet的Local属性可以访问当前context中被追踪且没有被标记为删除的实体(内存中的数据) 1 using (var context = new BloggingContext()) 2 { 3 // Load all blogs from the database into the context 4 context.Blogs.Load(); 5 6 // Add a new blog to the context 7 context.Blogs.Add(new Blog {

EF中的批量操作

阅读目录 插入 更新 删除 在使用EF的过程中,我们经常会遇到需要批量操作数据的场景,批量操作有的时候不仅能提高性能,比如使用SqlBulkCopy进入批量插入的时候,而且比较方便操作,提高效率.那么这篇文章就来总结EF中的那些批量操作. 回到顶部 插入 1,单个插入 单个插入很简单,只需要构造好实体,然后调用DbSet的Add方法,最后SaveChanges就行,示例代码如下. using (var db = new PackageFHContext()) { // 单个插入 var enti

EF中的Code First

EF中的Code First   一些概念 ? POCO POCO(Plain Old CLR Object)的概念是从java的POJO借用而来,而两者的含义是一致的,不同的仅仅是使用的语言不一样.所以POCO的解释就是“Plain Old C# Object”.POJO的内在含义是指那些没有从任何类继承.也没有实现任何接口,更没有被其它框架侵入的对象. ? PO PO是指持久对象(persistant object持久对象).持久对象实际上必须对应数据库中的entity,所以和POJO有所区