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

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

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

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

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

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

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

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

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

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

架构设计

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

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

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

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

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

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

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

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

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

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

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

□ 缓存接口

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

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

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

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

□ 视图模型

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

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

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

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

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

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

□ 初始化所有的Profile

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

□ 全局注册

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

关于AutoMapper的使用,在这里

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

MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射的更多相关文章

  1. MVC无限级分类02,增删改查

    继上一篇"MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射",本篇开始MVC无限级分类的增删改查部分,源码在github. 显示和查询 使用datagrid显 ...

  2. 说一说Web开发中两种常用的分层架构及其对应的代码模型

    昨天妹子让我帮她解决个问题,本以为可以轻松搞定,但是打开他们项目的一瞬间,我头皮发麻.本身功能不多的一个小项目,解决方案里竟然有几十个类库.仅仅搞明白各个类库的作用,代码层次之间的引用关系就花了一个多 ...

  3. 从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构

    Microsoft.AspNet.Identity简介 Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的mem ...

  4. 移动App设计之分层架构+MVC

    http://www.cnblogs.com/Logen/archive/2012/11/08/2760638.html 场景分析:我们知道,一个移动设备的应用大多与网络有关,也就是说,我在移动设备上 ...

  5. 无限级分类Asp.net Mvc实现

    无限级分类Asp.net Mvc实现   无限级分类涉及到异步加载子类.加载当前类和匹配问题,现在做一个通用的实现.   (一) 效果如下:   (二)设计.实现及使用 (1)数据库 (a)表设计db ...

  6. 左右值无限级分类 MVC + EntityFramework 的简单实现

    在度娘上查了大半个月的资料,最后发现每个网友分享的文章都有一定的错误(PS:大家是故意的么?).最后是在看了一个ASP版本后知道了大概流程:看了一个存储过程实现的文章后知道了大概需要的功能:看了一个S ...

  7. DDD分层架构之领域实体(验证篇)

    DDD分层架构之领域实体(验证篇) 在应用程序框架实战十四:DDD分层架构之领域实体(基础篇)一文中,我介绍了领域实体的基础,包括标识.相等性比较.输出实体状态等.本文将介绍领域实体的一个核心内容—— ...

  8. 【转载】DDD分层架构的三种模式

    引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...

  9. DDD分层架构的三种模式

    引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...

随机推荐

  1. sizeof求结构体大小

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

  2. jre安装配置!

    通常安装java开发环境都是jdk ,jre 一起安装,配置变量!分享一下只安装jre的配置! 去官网下载jre, 按提示安装成功! 和jdk配置一样 ,首先配置一下:JRE_HOME=C:\Prog ...

  3. Elasticsearch 6.x 的分页查询数据

    { , "query": { "match" : { "person_name" : "张老师" }}, , ], &q ...

  4. 《精通Python设计模式》学习之抽象工厂

    这种工厂模式用得少, 可能在游戏类的编程中用得比较多吧. 这个思路清晰一定要OK的. class Frog: def __init__(self, name): self.name = name de ...

  5. jquery图片延迟加载方案解决图片太多加载缓慢问题

    当在做一个图片展示站的时候,一个页面加载的图片过多会,如果服务器的带宽跟不上,明显会感觉到页面很卡,严重的浏览器也会崩溃,所以我推荐采用即看即所得的模式,当滚动到下一屏时才进行加载图片. 注意:即便如 ...

  6. USACO 6.3 Fence Rails(一道纯剪枝应用)

    Fence RailsBurch, Kolstad, and Schrijvers Farmer John is trying to erect a fence around part of his ...

  7. 更快的速度、更好的服务——易普优APS云排程

    众所周知软件执行效率受制于硬件性能,市面上的APS产品多为单机版本,企业要应用好APS,保证紧急插单.计划下发全程无忧,用户电脑硬件性能是不容忽视的一大瓶颈.APS的直接用户是车间管理人员.计划员,而 ...

  8. LoadRunner 参数化之 连接数据库进行参数化

    LoadRunner 参数化之 连接数据库进行参数化 Loadrunner(简称“LR”)对性能测试的脚本进行参数化时,由于数据量偏大,大家往往都会把数据录入到数据库表里,然后关联到LR,本文将详细介 ...

  9. 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:fhcq-oa' did not find a matching property.

    当你在使用Eclipse运行web项目时,你可能会看到控制台出现: 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Settin ...

  10. 001 Java 深拷贝、浅拷贝及Cloneable接口

    原本写过,后来在阅读的时候,感觉自己都不是太明白了,删除后参考人家的又重新写了一份. 一:开篇 1.复制一个变量 举例是int类型. 其他其中七种原始数据类型同样适用. 原始类型:boolean,ch ...