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,发现成功更新。

  • 相关阅读:
    ACM-超级楼梯
    clientt.c
    call.c
    answer.c
    aa.c
    client.c
    service.c
    自己动手开发jQuery插件
    apache-commons-net Ftp 进行文件、文件夹的上传下载及日志的输出
    在Eclipse中制作SSH配置文件提示插件
  • 原文地址:https://www.cnblogs.com/hpbkin/p/11269721.html
Copyright © 2011-2022 走看看