Entity Framework中数据缓存的问题

来源:互联网 发布:怎样建淘宝团购微信群 编辑:程序博客网 时间:2024/05/16 11:38

EF通过linq读取数据库数据的时候会在本地对数据进行缓存,以提高效率。如果缓存策略配置不对容易造成EF中返回的数据和DB中数据不同的情况,默认情况下本地已经存在的对象在读取数据库的时候不会进行更新。结觉这个问题的方法有:

1.避免使用全局的DBContext对象,在需要读取数据的时候实例化一个临时的DBContext对象

     using (PDSCoreDBContext innerContext = new PDSCoreDBContext())
            {
                
             
                var query = from b in innerContext.DataFileInfoes
                            where b.FirmId == workflowInstance.SubscriberFirmID && b.WorkflowInstanceId == workflowInstance.WorkflowInstanceId && b.DataFileInfoId > maxDataFileInfoId_Previous
                            select b;


                foreach (DataFileInfo item in query)
                {
                    fileInfoCollection.Add(item);
                    Console.WriteLine("Count:" + item.DownloadCount);
                }
            }

2.设置缓存策略(MergeOption):

MSDN:

AppendOnly
不会从数据源加载对象上下文中已存在的对象。这是查询或调用 EntityCollection<(Of <(TEntity>)>) 的 Load 方法时的默认行为。

OverwriteChanges
对象始终从数据源进行加载。数据源值会重写在对象上下文中对对象所做的任何属性更改。

PreserveChanges
当一个对象存在于对象上下文中时,不会从数据源加载该对象。保存在对象上下文中对对象所做的任何属性更改。

NoTracking
对象保持为 Detached 状态,也不在 ObjectStateManager 中进行跟踪。

AppendOnly

该状态下,无论是GetObjectByKey还是Where()都取到的是ObjectContext上的副本(携带Modified状态),没有真正访问数据库(后测试发现确实产生了数据查询,但是获取出来的值依然是上下文副本中的,并且这次查询并不会改变上下文中的CurrentValue和OriginalValue,即便上下文中实体为Modified状态。暂时不知道为什么会是这样的设计结果)。

OverwriteChanges
该状态下,GetObjectByKey获取到的依然是ObjectContext上的副本(携带Modified状态),但使用Where语句后,三个语句查出来的对象都被更改为数据库当前实际数据,状态。即,使用OverwriteChanges枚举调用Where语句,取出数据会覆盖当前ObjectContext上的数据以及关联的这些副本。
NoTracking
该状态相对比较简单,Where语句直接从数据库获取数据,并且状态为Detached,也不影响ObjectContext中的对象。

PreserveChanges
该状态可能是最难理解的。第一次测试时,发现类似于AppendOnly枚举,执行完后,三个语句查出来的对象都是在ObjectContext中Modified状态的原对象,可能没有访问数据库,我就奇怪那他和AppendOnly有什么区别呢?于是我把修改对象属性的那行代码注释掉后,也就是在ObjectContext中的对象状态为Unchanged,再去执行GetObjectByKey和Where()语句,这时候就发生变化了:Where语句直接取到了数据库中最新的数据,并把ObjectContext以及相关联的对象副本都进行了更新。
因此,PreserveChanges的意思是,如果对象属性被修改过,则保留修改记录,否则从数据库直接获取数据

MergeOption的使用:

1. Set the value of the EntitySet.MergeOption property

When you do this, any queries you create from the entity set will use the MergeOption value you specify. For example:

this.ObjectContext.EmployeeEntitySet.MergeOption = MergeOption.OverwriteChanges;
IQueryable<EmployeeEntity> query = from e in this.ObjectContext.EmployeeEntitySet
where e.EmployeeID == employeeID
select e;
return query.FirstOrDefault();

2. You can create an object query and set its MergeOption property

When you do this, the setting only applies to the current query. For example:

ObjectQuery<EmployeeEntity> query = this.ObjectContext.CreateQuery<EmployeeEntity>(“[EmployeeEntitySet]”);
query.MergeOption = MergeOption.OverwriteChanges;
var res = from ei n query
where e.EmployeeID == employeeID
select e;
return res.FirstOrDefault();

3. You can convert the IQueryable<T> into an object query, call Execute() and specify the MergeOption

This also sets the MergeOption on a specific query, rather than all queries of that type. For example:

IQueryable<EmployeeEntity> query = from e in this.ObjectContext.EmployeeEntitySet
where e.EmployeeID == employeeID
select e;
ObjectQuery objectQuery = (ObjectQuery)query;
ObjectResult<EmployeeEntity> result = (ObjectResult<EmployeeEntity>objectQuery.Execute(MergeOption.OverwriteChanges);
return result.FirstOrDefault();

把MergeOption设置为“NoTracking”也可以,但效率会下降。

也可直接设置:

 var query = from b in PDSCoreDBContextTest.DataFileInfoes.AsNoTracking()

                        where b.FirmId == workflowInstance.SubscriberFirmID && b.WorkflowInstanceId == workflowInstance.WorkflowInstanceId && b.DataFileInfoId > maxDataFileInfoId_Previous
                        select b;



0 0