上一篇文章中,曾经讲在Asp.Net中采用ADO.Net Entity做缓存的处理方式,就是继承默认的ObjectContext,在保存更新时,Detach所有被Attach过的实体。曾经认为是天衣无缝,其实根本没考虑到在附加实体后,保存更新前,这中间如果出现异常的情况。比如有一个页面有这样的语句:
var DB = new DBContext(); //实体上下文 var person = EmployeeHelper.GetPersonByID(id); //从缓存中取数据 DB.Attach(person); person.Name = "流川枫" ; person.JoinDate = DateTime.Parse(Request[ "date" ]); …… DB.SaveChanges(); |
如果Request["date"]不是一个有效的日期格式,页面在执行到DB.SaveChanges()之前就会抛出异常,不但本次修改失败,而且以后所有试图修改此条记录的请求也将失败,直到此条记录的缓存过期。
因此,我们仍然需要保证在即使保存失败,缓存的实体也能从实体上下文脱离,继续保持可更新的机制。就脱离上下文的方式,我试过好几种方式,最终唯一靠谱的就是:将这个上下文彻底销毁,皮之不存,毛将焉附。所以,虽然不情愿,却必须建立对实体上下文的跟踪管理机制。
跟踪管理又可以有两条路,一种是采用建立资源池方式,这种是比较正统合理的方案,但我相信AEF将来会改进的。所以我目前采用了第二种方式:实体上下文与HttpContext绑定,并在Application_EndRequest事件中执行清理。
实体上下文构造函数:
public DBContext() { var items = HttpContext.Current.Items; items[ "dbContext" + items.Count] = this ; } |
Global.asax中的函数:
void Application_EndRequest( object sender, EventArgs e) { foreach ( var item in this .Context.Items.Values) { var disposableObj = item as IDisposable; if (disposableObj != null ) disposableObj.Dispose(); } } |
这个问题一波三折,困扰了两个月。虽然看上去很简单地解决了,但是还是不太爽,没更多时间和能力研究更深层的东西了。Visual Studio 2010发布会上一句口号是:Coding完美世界,很多时候,完美其实是只是一个传说。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步