zoukankan      html  css  js  c++  java
  • MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射

    本系列将使用zTree来创建、编辑关于品牌、车系、车型的无限级分类,使用datagrid显示,源码在github。先上最终效果:

    datagrid显示所有记录、分页,提供添加、修改、删除按钮,并提供简单搜索:
    1

    创建分类,弹出模态窗口,zTree显示所有分类,点击勾选按钮或节点,所选节点名称显示到文本框:
    2
    3

    提供客户端和服务端验证,验证不通过显示出错信息:
    4

    修改分类,弹出模态窗口,zTree显示当前选中的节点名称:
    5

      创建数据模型并生成到数据库

    →创建CarModel.edmx,创建模型,无限级分类的一切"神奇"从ParentID字段开始。

    6

    →右键界面,选择"根据模型生成数据库"

    7

    →配置数据库连接,运行sql语句......等等,最终生成如下文件:

    8

    ● App.config中的连接字符串需要复制到MVC主站点的web.config中。
    ● CarModel.Context.cs中包含了继承DbContext的上下文。
    ● CarModel.tt下包含了所有的领域模型Domain Models。
    ● CarModel.edmx.sql每次映射完执行里面的sql语句,将把数据同步到数据库。

      架构设计

    由于主要是体验无限级分类的增删改查,架构做得相对简单一些。其它组件列举的只是示意,实际只用到了缓存和序列化json的帮助类。如下:

    structure

    □ IBaseRepository是接口的基类,提供了所有接口的泛型实现

    using System; 
    using System.Collections.Generic; 
    using System.Linq.Expressions;
     
    namespace Car.Test.DAL 
    { 
        public interface IBaseRepository<T> where T : class,new() 
        { 
            IEnumerable<T> LoadEntities(Expression<Func<T, bool>> whereLambda); 
            IEnumerable<T> LoadEntitiesByCache(Expression<Func<T, bool>> whereLambda); 
            T AddEntity(T entity); 
            T UpdateEntity(T entity); 
            void ClearCache(); 
            int SaveChanges(); 
        } 
    }

    □ 其它接口只需要继承该基类接口就可以

    namespace Car.Test.DAL 
    { 
        public interface ICarCategoryRepository : IBaseRepository<Car.Test.Model.CarCategory> 
        { 
             
        } 
    }

    当然,如果Domain Model很多的话,这样写方便tt模版自动生成。

    □ BaseRepository是Repository的基类,提供了所有Repository的泛型实现

    提供了针对泛型的增删改查,还包括缓存查询,提交变化。

    using System.Data; 
    using System.Linq; 
    using Car.Test.Cache; 
    using Car.Test.Model; 
    using System; 
    using System.Collections.Generic; 
    using System.Linq.Expressions;
     
    namespace Car.Test.DAL 
    { 
        public class BaseRepository<T> where T:class,new() 
        { 
            protected CarModelContainer DataContext { get; private set; } 
            public ICacheProvider Cache { get; set; }
     
            public BaseRepository(ICacheProvider cacheProvider) 
            { 
                this.DataContext = new CarModelContainer(); 
                this.Cache = cacheProvider; 
            }
     
            public BaseRepository():this(new DefaultCacheProvider()){}
     
            public virtual IEnumerable<T> LoadEntities(Expression<Func<T, bool>> whereLambda) 
            { 
                IEnumerable<T> temp = DataContext.Set<T>().Where(whereLambda).AsEnumerable(); 
                return temp; 
            }
     
            public virtual IEnumerable<T> LoadEntitiesByCache(Expression<Func<T, bool>> whereLambda) 
            { 
                IEnumerable<T> entities = Cache.Get(typeof(T).ToString()) as IEnumerable<T>; 
                if (entities == null) 
                { 
                    entities = DataContext.Set<T>().Where(whereLambda).AsEnumerable(); 
                    if (entities.Any()) 
                    { 
                        Cache.Set(typeof(T).ToString(),entities,3); 
                    } 
                } 
                return entities; 
            }
     
            public virtual T AddEntity(T entity) 
            { 
                DataContext.Set<T>().Add(entity); 
                return entity; 
            }
     
            public virtual T UpdateEntity(T entity) 
            { 
                if (entity != null) 
                { 
                    DataContext.Set<T>().Attach(entity); 
                    DataContext.Entry(entity).State = EntityState.Modified;
     
                } 
                return entity; 
            }
     
            public void ClearCache() 
            { 
                Cache.InValidate(typeof(T).ToString()); 
            }
     
            public int SaveChanges() 
            { 
                return DataContext.SaveChanges(); 
            } 
        } 
    }
     

    □ 其它Repository只需继承BaseRepository并实现各自的接口

    namespace Car.Test.DAL 
    { 
        public class CarCategoryRepository : BaseRepository<Car.Test.Model.CarCategory>,ICarCategoryRepository 
        { 
             
        } 
    }

    □ 缓存接口

    namespace Car.Test.Cache 
    { 
        public interface ICacheProvider 
        { 
            object Get(string key); 
            void Set(string key, object data, int cacheTime); 
            bool IsSet(string key); 
            void InValidate(string key); 
        } 
    }

    □ 缓存实现,需要引入System.Runtime.Caching

    using System; 
    using System.Runtime.Caching;
     
    namespace Car.Test.Cache 
    { 
        public class DefaultCacheProvider : ICacheProvider 
        { 
            private ObjectCache Cache 
            { 
                get { return MemoryCache.Default; } 
            }
     
            public object Get(string key) 
            { 
                return Cache[key]; 
            }
     
            public void Set(string key, object data, int cacheTime) 
            { 
                CacheItemPolicy policy = new CacheItemPolicy(); 
                policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime); 
                Cache.Add(new CacheItem(key, data), policy); 
            }
     
            public bool IsSet(string key) 
            { 
                return Cache[key] != null; 
            }
     
            public void InValidate(string key) 
            { 
                Cache.Remove(key); 
            } 
        } 
    }
     

      使用AutoMapper映射领域模型和视图模型

    □ 视图模型

    using DataAnnotationsExtensions; 
    using System.ComponentModel.DataAnnotations;
     
    namespace Car.Test.Portal.Models 
    { 
        public class CarCategoryVm 
        { 
            public int ID { get; set; }
     
            [Display(Name = "类名")] 
            [Required(ErrorMessage = "必填")] 
            [StringLength(10, MinimumLength = 2,ErrorMessage = "长度2-10位")] 
            public string Name { get; set; }
     
            [Display(Name = "前缀字母")] 
            [Required(ErrorMessage = "必填")] 
            [StringLength(1,ErrorMessage = "长度1位")] 
            public string PreLetter { get; set; }
     
            [Display(Name = "所属父级")] 
            [Required(ErrorMessage = "必填")] 
            public int ParentID { get; set; }
     
            public System.DateTime SubTime { get; set; }
     
            [Display(Name = "层级(根节点为0级)")] 
            [Required(ErrorMessage = "必填")] 
            [Min(1, ErrorMessage = "至少为1")] 
            public int Level { get; set; }
     
            [Display(Name = "是否为页节点")] 
            [Required(ErrorMessage = "必填")] 
            public bool IsLeaf { get; set; }
     
            public short Status { get; set; } 
            public short DelFlag { get; set; } 
        } 
    }
     

    引入DataAnnotationsExtensions组件,通过它可以设置最小值,关于DataAnnotationsExtensions的使用,在这里

    □ 继承AutoMapper的Profile类,创建领域模型→视图模型映射

    using AutoMapper; 
    using Car.Test.Model; 
    using Car.Test.Portal.Models;
     
    namespace Car.Test.Portal.Helpers.AutoMapper 
    { 
        public class DomainToVmProfile : Profile 
        { 
            protected override void Configure() 
            { 
                Mapper.CreateMap<CarCategory, CarCategoryVm>(); 
            } 
        } 
    }
     

    □ 继承AutoMapper的Profile类,创建视图模型→领域模型映射

    using AutoMapper; 
    using Car.Test.Model; 
    using Car.Test.Portal.Models;
     
    namespace Car.Test.Portal.Helpers.AutoMapper 
    { 
        public class VmToDomainProfile : Profile 
        { 
            protected override void Configure() 
            { 
                Mapper.CreateMap<CarCategoryVm, CarCategory>() 
                    .ForMember("Car", opt => opt.Ignore()); 
            } 
        } 
    }
     

    □ 初始化所有的Profile

    using AutoMapper;
     
    namespace Car.Test.Portal.Helpers.AutoMapper 
    { 
        public static class AutoMapperConfiguration 
        { 
            public static void Configure() 
            { 
                Mapper.Initialize(x => x.AddProfile<VmToDomainProfile>()); 
                Mapper.Initialize(x => x.AddProfile<DomainToVmProfile>()); 
            } 
        } 
    }
     

    □ 全局注册

            protected void Application_Start() 
            { 
                AreaRegistration.RegisterAllAreas();
     
                WebApiConfig.Register(GlobalConfiguration.Configuration); 
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
                RouteConfig.RegisterRoutes(RouteTable.Routes); 
                BundleConfig.RegisterBundles(BundleTable.Bundles);
     
                //全局配置映射 
                AutoMapperConfiguration.Configure(); 
            }

    关于AutoMapper的使用,在这里

    下篇进入无限级分类的增删改查环节。   

  • 相关阅读:
    取消浏览器默认行为
    BootStrap基础
    JavaScript基础
    HTML和CSS基础
    03JDBC
    MySQL
    NER-BiLSTM+CRF
    pytroch-Dataset/DataLoader/collate_fn/pad_sequence方法介绍
    pytorch-LSTM()简单介绍
    NER-使用kashgari中的Bert+BiLSTM+CRF
  • 原文地址:https://www.cnblogs.com/darrenji/p/3674418.html
Copyright © 2011-2022 走看看