MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射
本系列将使用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是接口的基类,提供了所有接口的泛型实现
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的使用,在这里。
下篇进入无限级分类的增删改查环节。
MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射的更多相关文章
- MVC无限级分类02,增删改查
继上一篇"MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射",本篇开始MVC无限级分类的增删改查部分,源码在github. 显示和查询 使用datagrid显 ...
- 说一说Web开发中两种常用的分层架构及其对应的代码模型
昨天妹子让我帮她解决个问题,本以为可以轻松搞定,但是打开他们项目的一瞬间,我头皮发麻.本身功能不多的一个小项目,解决方案里竟然有几十个类库.仅仅搞明白各个类库的作用,代码层次之间的引用关系就花了一个多 ...
- 从Microsoft.AspNet.Identity看微软推荐的一种MVC的分层架构
Microsoft.AspNet.Identity简介 Microsoft.AspNet.Identity是微软在MVC 5.0中新引入的一种membership框架,和之前ASP.NET传统的mem ...
- 移动App设计之分层架构+MVC
http://www.cnblogs.com/Logen/archive/2012/11/08/2760638.html 场景分析:我们知道,一个移动设备的应用大多与网络有关,也就是说,我在移动设备上 ...
- 无限级分类Asp.net Mvc实现
无限级分类Asp.net Mvc实现 无限级分类涉及到异步加载子类.加载当前类和匹配问题,现在做一个通用的实现. (一) 效果如下: (二)设计.实现及使用 (1)数据库 (a)表设计db ...
- 左右值无限级分类 MVC + EntityFramework 的简单实现
在度娘上查了大半个月的资料,最后发现每个网友分享的文章都有一定的错误(PS:大家是故意的么?).最后是在看了一个ASP版本后知道了大概流程:看了一个存储过程实现的文章后知道了大概需要的功能:看了一个S ...
- DDD分层架构之领域实体(验证篇)
DDD分层架构之领域实体(验证篇) 在应用程序框架实战十四:DDD分层架构之领域实体(基础篇)一文中,我介绍了领域实体的基础,包括标识.相等性比较.输出实体状态等.本文将介绍领域实体的一个核心内容—— ...
- 【转载】DDD分层架构的三种模式
引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...
- DDD分层架构的三种模式
引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...
随机推荐
- OBJECT_ID()的使用方法
数据库中每个对像都有一个唯一的ID值,用Object_name(id)可以根据ID值得到对像的名称,object_id(name)可以根据对像名称得到对象的ID object_id()只能返回用户创建 ...
- 接口测试工具--Poster与Postman的简单实用
HTTP/SOAP协议接口的功能测试: 1.浏览器URL(GET请求) http://127.0.0.1:8000/login/?username=zhangsan&password=1234 ...
- git status中文文件名编码问题解决
在默认设置下,中文文件名在工作区状态输出,中文名不能正确显示,而是显示为八进制的字符编码. 通过将git配置变量 core.quotepath 设置为false,就可以解决中文文件名称在这些Git命令 ...
- lr11录制时报“Request Connection: Remote Server @ 0.0.0.0:1080 (Service=?) NOT PROXIED! )”解决方法
在录制脚本的时候出现如下现象: 解决方法: LoadRunner录制脚本时出现:Unable to connect to remote server),有事件没有脚本的问题 1.首先要查看IE浏览 ...
- HashMap 在 Java1.7 与 1.8 中的区别
hashMap 数据结构 如上图所示,JDK7之前hashmap又叫散列链表:基于一个数组以及多个链表的实现,hash值冲突的时候,就将对应节点以链表的形式存储. JDK8中,当同一个hash值(Ta ...
- Ionic入门三:列表
列表是一个应用广泛的界面元素,在所有移动app中几乎都会使用到. 列表可以是基本文字.按钮,开关,图标和缩略图等. 列表项可以是任何的HTML元素.容器元素需要list类,每个列表项需要使用item类 ...
- 洛谷P2525 Uim的情人节礼物·其之壱 [康托展开]
题目传送门 Uim的情人节礼物·其之壱 题目描述 情人节到了,Uim打算给他的后宫们准备情人节礼物.UIm一共有N(1<=N<=9)个后宫妹子(现充去死 挫骨扬灰!). 为了维护他的后宫的 ...
- linux/mac下命令行rm回收站--rmtrash
Linux.mac的命令行下没有回收站功能,很多时候手一抖就把重要文件给 rm -fr * 了,虽然linux下有可能通过lost +found/debugfs找回,但难度也比较大,不能保证一定能够找 ...
- EL表达式和JSTL标准标签库
一.EL表达式 什么是EL表达式 EL(Express Lanuage)表达式可以嵌入在jsp页面内部 减少jsp脚本的编写 EL出现的目的是要替代jsp页面中脚本的编写. EL表达式的作用 EL最主 ...
- codevs 5971 打击犯罪
5971 打击犯罪 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 某个地区有n(n<=1000)个犯罪团伙,当地警方按照他们 ...