zoukankan      html  css  js  c++  java
  • nopCommerce中缓存学习

    最近把后台管理程序换成nop方式。

    在使用_productService.Update(M); 时碰到问题,更新不成功。

    刚开始还以为是EF的问题,因为是先_productService.GetProductById(id), 再update,难道get的实体类不是要更新的数据吗?

    然后查了下EF更新的三种情况:

    1.最基本的,先查出来再更新,EF会跟踪查询的结果,看是否有新的更新,如果有只更新修改的字段,如果没有修改内容则不更新数据库。

                TestDbContext db = new TestDbContext();
                var test = db.Tests.Find(1);
                test.Remarks = "更新字段方法1";
    
                db.SaveChanges();            

    2.比第一种情况少了查询步骤。先New一个实体类并且赋值,再通过dbcontext的db.Entry(test).State设置该实体类对应的状态是modified,然后savechange()即可,此方法会更新表的每个字段,没有赋值就是Null。

                TestDbContext db = new TestDbContext();
                Test test = new Test() { ID = 1, Remarks = "更新字段方法2" };
                db.Entry(test).State = System.Data.Entity.EntityState.Modified;
    
                db.SaveChanges();

    3.也不用先查询该数据,而且不会更新全部字段,只更新设置了IsModified = true的字段。New一个实体类并赋值,db.Tests.Attach(test);把该实体类添加到dbcontext,然后db.Entry(test).Property("Remarks").IsModified = true;对需要修改的字段设置属性,只会对设置属性的字段更新。

                TestDbContext db = new TestDbContext();
                Test test = new Test() { ID = 1, Remarks = "更新字段方法3" };
                db.Tests.Attach(test);
                db.Entry(test).Property("Remarks").IsModified = true;
    
                db.SaveChanges();

    使用 SQL Server Profiler 跟踪数据库发现_productService.GetProductById(id)这个步骤没有产生sql语句,进去该方法,猜测应该是缓存的问题,确定不是EF的问题。

    _productService.GetProductById方法:

            public M_Device GetProductById(int productId)
            {
                if (productId == 0)
                    return null;
    
                string key = string.Format(BSRPRODUCTS_BY_ID_KEY, productId);
                return _cacheManager.Get(key, () => _productRepository.GetById(productId));
            }

    其中: _cacheManager.Get(key, () => _productRepository.GetById(productId)) 是先查 _cacheManager.Get<M_Device>(key)看是否有值,否则执行后面的lambda表达式。

    调试发现_cacheManager.Get<M_Device>(key)一直有值,难怪更新不成功,是因为没有执行GetById方法。

    查nop代码:

    nop有三种缓存:HttpContextBase.Items键值对、Redis、MemoryCache。

    在依赖注入程序里有:

           if (config.RedisCachingEnabled)
                {
                    builder.RegisterType<RedisConnectionWrapper>().As<IRedisConnectionWrapper>().SingleInstance();
                    builder.RegisterType<RedisCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").InstancePerLifetimeScope();
                }
                else
                {
                    builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
                }
                builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerLifetimeScope();

    Redis 和 MemoryCache 会二选一,我的程序中暂时使用的 MemoryCache 。

    在CacheExtensions.cs里看到默认有效期是60分钟。

    调试发现return _cacheManager.Get(key, () => _productRepository.GetById(productId)); 里的cache竟然是 MemoryCache(估计是因为在注入程序中把PerRequestCache的实例化注销了导致)。

    builder.RegisterType<bsrProductService>().As<IbsrProductService>().InstancePerLifetimeScope();

    一般service里的cache默认是PerRequestCache。如果要注入 MemoryCache需要传入参数:

    builder.RegisterType<bsrProductController>()
    .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));

    查了下PerRequestCache的 HttpContextBase.Items键值对,

       HttpContext基于HttpApplication的处理管道,由于HttpContext对象贯穿整个处理过程,所以,可以从HttpApplication处理管道的前端将状态数据传递到管道的后端,完成状态的传递任务。
    
      HttpContext的生命周期从服务器接收的HTTP请求开始到反应发送回客户端结束。
    
      在WebForm或类库(包括MVC)项目中,通过Current静态属性,就能够获得HttpContext的对象。
    
      HttpContext context = HttpContext.Current;
      如果是在Asp.net MVC的Controller中,通过this.HttpContext;就能获取到HttpContextBase对象。
    
      HttpContextBase context = this.HttpContext;
      如果是在MVC视图中可以这样得到:
    
      @Html.ViewContext.HttpContext
      在MVC中是HttpContextBase在WebForm中是HttpContext。
    HttpContext的Items是IDictionary键/值对的对象集合,在HttpRequest的生存期中共享。它只存在于HttpRequest中。

    所以:

    点击编辑进入详情页的时候虽然调用了_productService.GetProductById(id), 缓存了该条数据(HttpContextBase.Items缓存,客户端显示正常后缓存就结束了), 编辑数据点击保存后,

    先调用 _productService.GetProductById(id) 即 return _cacheManager.Get(key, () => _productRepository.GetById(productId));  里的cache并没有该值,因为点击保存又是另外的HttpRequest了。再update,发现成功更新。

  • 相关阅读:
    飞入飞出效果
    【JSOI 2008】星球大战 Starwar
    POJ 1094 Sorting It All Out
    POJ 2728 Desert King
    【ZJOI 2008】树的统计 Count
    【SCOI 2009】生日快乐
    POJ 3580 SuperMemo
    POJ 1639 Picnic Planning
    POJ 2976 Dropping Tests
    SPOJ QTREE
  • 原文地址:https://www.cnblogs.com/hpbkin/p/11269721.html
Copyright © 2011-2022 走看看