同一个DbContext实例,EF会对查询过的数据进行缓存。对DbContext的生存期的管理需根据当前的应用来处理(如web、win),尽量不要采用全局的DbContext。也可在查询中采用AsNoTracking避免从缓存中取数据。

1、问题

构建一个全局的或某个业务场景内唯一的DbContext

public OTBll()

{

efContext = new AppDbContext();

this.OT_DataFlowRepository = new EFRepository(efContext);

在此场景内间隔查询数据

HR_SignSealPdf entity =context.HR_SignSealPdf.FirstOrDefault(e =>

e.SignId == item.SignId && e.Cate == item.Cate);

entity.PdfUploadErrs += 1;

SSMS修改PdfUploadErrs后,仍会从entity.PdfUploadErrs的值上累加

UPDATE HR_SignSealPdf SET PdfUploadErrs=0

2、解决办法

(1)每次构建一个新的DbContext实例,使用完毕就释放

using (var context = new AppDbContext())

{

...

}

(2)AsNoTracking返回新的查询实体

efContext.HR_SignSealPdf.AsNoTracking()

反编译的代码

///

返回一个新查询,其中返回的实体将不会在 中进行缓存。此方法通过调用基础查询对象的 AsNoTracking 方法来运行。如果基础查询对象没有 AsNoTracking 方法,则调用此方法将不会有任何影响。

/// 应用 NoTracking 的新查询,如果不支持 NoTracking,则为源查询。

/// 源查询。

public static IQueryable AsNoTracking(this IQueryable source)

{

System.Data.Entity.Utilities.Check.NotNull(source, nameof (source));

DbQuery dbQuery = source as DbQuery;

if (dbQuery == null)

return QueryableExtensions.CommonAsNoTracking(source);

return (IQueryable) dbQuery.AsNoTracking();

}

3、优化

(1)web端可考虑在当前操作线程内定义个唯一的DbContext,以提高效率

//返回当前线程内的数据库上下文,如果当前线程内没有上下文,那么创建一个上下文,并保证上线问实例在线程内部是唯一的

public static VpoEntities GetCurrentDemoContext()

{

//CallContext:是线程内部唯一的独用的数据槽(一块内存空间)

//传递DbContext进去获取实例的信息,在这里进行强制转换。

VpoEntities dbContext = CallContext.GetData("DbContext") as VpoEntities;

if (dbContext == null) //线程在数据槽里面没有此上下文

{

dbContext = new VpoEntities(); //如果不存在上下文的话,创建一个EF上下文

var adapter = (IObjectContextAdapter)dbContext;

var objectContext = adapter.ObjectContext;

objectContext.CommandTimeout = 1800;

//我们在创建一个,放到数据槽中去

CallContext.SetData("DbContext", dbContext);

}

return dbContext;

}