上一篇文章中,曾经讲在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完美世界,很多时候,完美其实是只是一个传说。

posted on 2011-04-11 00:30  小城故事  阅读(934)  评论(0编辑  收藏  举报