前一段时间,写了一步一步asp.net的一系列博客,最近,也快要大四,忙着准备找个工作,这也算是最后一个假期了,这个系列可能不太长,尽量写完.还是多学习,少扯淡的风格,我们的学习还好
继续,现在开始学习asp.net MVC系列,基础知识,大家看博客园相关的一系列就可以了,我们在
这里学一下一个权限管理的设计.我采用的是Asp.net MVC+EF+N层的方式,顺便加入点
spring.net注入的部分,当然我们最主要的还是关于权限设计的部分.而架构,咱也没学过太复
杂的架构,我们还是从最常用的三层架构进行扩展.
参考书籍:
<<重构,改善既有代码的设计>>
<<.net应用架构设计原则,模式与实践>>
<<.net设计范式>>
<<代码整洁之道>>
以及网上众多的教程,博客等等
首先,我们要讲解一下关于项目的搭建部分.我们的项目主要分为5部分,业务逻辑层,数据访问层,界面层,领域模型层以及
一个公共类的部分.
当然,我们要先建立一个工程,并建立相应的解决方案文件夹,并且保持清晰程度,我们在工程加上前缀(最好是公司前缀)后面加上部分.
然后在每个解决方案文件夹下面建立响应的项目,
这里主要是:
业务逻辑层:
TZHSWEET.IBLL:业务逻辑层接口
TZHSWEET.BLL:业务逻辑层实现
数据访问层:
TZHSWEET.IDao:数据访问层接口
TZHSWEET.Dao:数据访问层实现
领域模型层:
TZHSWEET.Entity:这是EF建立的模型
TZHSWEET.ViewModel:这个是用来传递UI层和业务逻辑层的相关模型对象
界面层:
TZHSWEET.WebUI:主要的MVC和LigerUI实现的界面部分
TZHSWEET.UI:关于MVC公共UI定义的部分
公共类库部分:
TZHSWEET.CacheStorage主要是常用的缓存
TZHSWEET.Common主要是一些公共类实现等等
这里仅仅是三层架构按照我自己的想法做了一个适应性扩展,呵呵.
EF不用说了,这里只是一个简单的应用
在这里我先讲解关于Idao和Dao部分
我们的目标是"0"增删改查的数据访问层实现,
主要是靠EF的定义通用的增删改查,然后其他类继承增删改查接口和相应的自定义子类接口,实现扩展.
首先,我们从以前写代码的经验知道,我们的Dao主要是做增删改查等方面,我们就先定义一个公共的接口,叫做IBaseDao,这个接口定义泛型的增删改查,
1: /* 作者: tianzh
2: * 创建时间: 2012/7/16 11:01:34
3: *
4: */
5: using System;
6: using System.Collections.Generic;
7: using System.Linq;
8: using System.Text;
9: using System.Data.Objects;
10:
11: namespace TZHSWEET.IDao
12: {
13: public interface IBaseDao<T>// where T:class //限制class
14: {
15: #region 查询普通实现方案(基于Lambda表达式的Where查询)
16: /// <summary>
17: /// 获取所有Entity
18: /// </summary>
19: /// <param name="exp">Lambda条件的where</param>
20: /// <returns></returns>
21: IEnumerable<T> GetEntities(Func<T, bool> exp);
22:
23: /// <summary>
24: /// 计算总个数(分页)
25: /// </summary>
26: /// <param name="exp">Lambda条件的where</param>
27: /// <returns></returns>
28: int GetEntitiesCount(Func<T, bool> exp);
29:
30: /// <summary>
31: /// 分页查询(Linq分页方式)
32: /// </summary>
33: /// <param name="pageNumber">当前页</param>
34: /// <param name="pageSize">页码</param>
35: /// <param name="orderName">lambda排序名称</param>
36: /// <param name="sortOrder">排序(升序or降序)</param>
37: /// <param name="exp">lambda查询条件where</param>
38: /// <returns></returns>
39: IEnumerable<T> GetEntitiesForPaging(int pageNumber, int pageSize, Func<T, string> orderName, string sortOrder, Func<T, bool> exp);
40:
41: /// <summary>
42: /// 根据条件查找
43: /// </summary>
44: /// <param name="exp">lambda查询条件where</param>
45: /// <returns></returns>
46: T GetEntity(Func<T, bool> exp);
47:
48: #endregion
49: #region 查询Sql语句外接接口的查询实现
50: /// <summary>
51: /// 获取所有Entity(立即执行请使用ToList()
52: /// </summary>
53: /// <param name="CommandText">Sql语句</param>
54: /// <param name="objParams">可变参数</param>
55: /// <returns></returns>
56: IEnumerable<T> GetEntities(string CommandText);
57:
58: /// <summary>
59: /// 计算总个数(分页)
60: /// </summary>
61: /// <param name="CommandText">Sql语句</param>
62: /// <param name="objParams">可变参数</param>
63: /// <returns></returns>
64: int GetEntitiesCount(string CommandText);
65:
66: /// <summary>
67: /// 分页查询(Linq分页方式)
68: /// </summary>
69: /// <param name="tableName">表名</param>
70: /// <param name="pageNumber">当前页</param>
71: /// <param name="pageSize">页码</param>
72: /// <param name="orderName">lambda排序名称</param>
73: /// <param name="sortOrder">排序(升序or降序)</param>
74: /// <param name="CommandText">Sql语句</param>
75: /// <param name="Count">总个数</param>
76: /// <returns></returns>
77: IEnumerable<T> GetEntitiesForPaging(string tableName, int pageNumber, int pageSize, string orderName, string sortOrder, string CommandText, out int Count);
78:
79: /// <summary>
80: /// 根据条件查找
81: /// </summary>
82: /// <param name="CommandText">Sql语句</param>
83: /// <param name="objParams">可变参数</param>
84: /// <returns></returns>
85: T GetEntity(string CommandText);
86:
87: #endregion
88: /// <summary>
89: /// 插入Entity
90: /// </summary>
91: /// <param name="model"></param>
92: /// <returns></returns>
93: bool Insert(T entity);
94: /// <summary>
95: /// 更新Entity
96: /// </summary>
97: /// <param name="model"></param>
98: /// <returns></returns>
99: bool Update(T entity);
100: /// <summary>
101: /// 删除Entity
102: /// </summary>
103: /// <param name="entity"></param>
104: /// <returns></returns>
105: bool Delete(T entity);
106: }
107: }
接下来,我们需要定义一系列的接口继承这个接口,代码类似:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using TZHSWEET.Entity;
6:
7: namespace TZHSWEET.IDao
8: {
9:
10: public interface IDepartmentDao<T> : IBaseDao<T> where T : class
11: {
12:
13: }
14: }
这层接口,大家可能认为没什么必要,但是,这个接口非常重要,这个接口保证了我们用EF一个抽象类实现增删改查的同时又增加了子类的自身扩展性.
接下来,就是Dao部分,我们需要很慎重的去设计,
首先我们要设计一个用EF实现的公共父类的BaseEFDao类,用他来实现增删改查,
1: /* 作者: tianzh
2: * 创建时间: 2012/7/16 11:06:16
3: *
4: */
5: using System;
6: using System.Collections.Generic;
7: using System.Linq;
8: using System.Text;
9: using TZHSWEET.IDao;
10: using TZHSWEET.Entity;
11: using System.Data;
12: using TZHSWEET.Common;
13: using System.Data.Objects;
14: namespace TZHSWEET.EFDao
15: {
16: /// <summary>
17: /// 公共接口
18: /// </summary>
19: public class BaseEFDao<T> : IBaseDao<T> where T : class,new() //限制T为class
20: {
21:
22: #region 查询普通实现方案(基于Lambda表达式的Where查询)
23: /// <summary>
24: /// 获取所有Entity
25: /// </summary>
26: /// <param name="exp">Lambda条件的where</param>
27: /// <returns></returns>
28: public virtual IEnumerable<T> GetEntities(Func<T, bool> exp)
29: {
30:
31: using (BaseManageEntities Entities = new BaseManageEntities())
32: {
33: return Entities.CreateObjectSet<T>().Where(exp).ToList();
34: }
35:
36: }
37: /// <summary>
38: /// 计算总个数(分页)
39: /// </summary>
40: /// <param name="exp">Lambda条件的where</param>
41: /// <returns></returns>
42: public virtual int GetEntitiesCount(Func<T, bool> exp)
43: {
44: using (BaseManageEntities Entities = new BaseManageEntities())
45: {
46: return Entities.CreateObjectSet<T>().Where(exp).Count();
47: }
48: }
49: /// <summary>
50: /// 分页查询(Linq分页方式)
51: /// </summary>
52: /// <param name="pageNumber">当前页</param>
53: /// <param name="pageSize">页码</param>
54: /// <param name="orderName">lambda排序名称</param>
55: /// <param name="sortOrder">排序(升序or降序)</param>
56: /// <param name="exp">lambda查询条件where</param>
57: /// <returns></returns>
58: public virtual IEnumerable<T> GetEntitiesForPaging(int pageNumber, int pageSize, Func<T, string> orderName, string sortOrder, Func<T, bool> exp)
59: {
60: using (BaseManageEntities Entities = new BaseManageEntities())
61: {
62: if (sortOrder=="asc") //升序排列
63: {
64: return Entities.CreateObjectSet<T>().Where(exp).OrderBy(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
65: }
66: else
67: return Entities.CreateObjectSet<T>().Where(exp).OrderByDescending(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
68: }
69:
70: }
71: /// <summary>
72: /// 根据条件查找
73: /// </summary>
74: /// <param name="exp">lambda查询条件where</param>
75: /// <returns></returns>
76: public virtual T GetEntity(Func<T, bool> exp)
77: {
78: using (BaseManageEntities Entities = new BaseManageEntities())
79: {
80: return Entities.CreateObjectSet<T>().Where(exp).SingleOrDefault();
81: }
82: }
83: #endregion
84: #region 查询Entity To Sql语句外接接口的查询实现
85: /// <summary>
86: /// 获取所有Entity(立即执行请使用ToList()
87: /// </summary>
88: /// <param name="CommandText">Sql语句</param>
89: /// <param name="objParams">可变参数</param>
90: /// <returns></returns>
91: public virtual IEnumerable<T> GetEntities(string CommandText)
92: {
93:
94: using (BaseManageEntities Entities = new BaseManageEntities())
95: {
96: return Entities.ExecuteStoreQuery<T>("select * from "+typeof(T).Name+" where "+CommandText).ToList();
97: }
98:
99: }
100: /// <summary>
101: /// 计算总个数(分页)
102: /// </summary>
103: /// <param name="CommandText">Sql语句</param>
104: /// <returns></returns>
105: public virtual int GetEntitiesCount(string CommandText)
106: {
107: using (BaseManageEntities Entities = new BaseManageEntities())
108: {
109: return Entities.ExecuteStoreQuery<T>("select * from " +typeof(T).Name+ " where "+CommandText).Count();
110: }
111: }
112:
113: /// <summary>
114: /// 分页查询(Linq分页方式)
115: /// </summary>
116: /// <param name="tableName">表名</param>
117: /// <param name="pageNumber">当前页</param>
118: /// <param name="pageSize">页码</param>
119: /// <param name="orderName">lambda排序名称</param>
120: /// <param name="sortOrder">排序(升序or降序)</param>
121: /// <param name="CommandText">Sql语句</param>
122: /// <param name="Count">总个数</param>
123: /// <returns></returns>
124: public virtual IEnumerable<T> GetEntitiesForPaging(string tableName, int pageNumber, int pageSize, string orderName, string sortOrder, string CommandText,out int Count)
125: {
126: PaginationHelper pager = new PaginationHelper(tableName, orderName, pageSize, pageNumber, sortOrder, CommandText);
127: pager.GetSelectTopByMaxOrMinPagination();
128: using (BaseManageEntities Entities = new BaseManageEntities())
129: {
130: Count =GetEntitiesCount(CommandText);
131: return Entities.ExecuteStoreQuery<T>(pager.GetSelectTopByMaxOrMinPagination()).ToList();
132:
133: }
134:
135: }
136: /// <summary>
137: /// 根据条件查找
138: /// </summary>
139: /// <param name="CommandText">Sql语句</param>
140: /// <param name="objParams">可变参数</param>
141: /// <returns></returns>
142: public virtual T GetEntity(string CommandText)
143: {
144: using (BaseManageEntities Entities = new BaseManageEntities())
145: {
146: return Entities.ExecuteStoreQuery<T>("select * from "+typeof(T).Name+" where "+CommandText).SingleOrDefault();
147: }
148: }
149: #endregion
150: #region 增删改实现
151: /// <summary>
152: /// 插入Entity
153: /// </summary>
154: /// <param name="model"></param>
155: /// <returns></returns>
156: public virtual bool Insert(T entity)
157: {
158: using (BaseManageEntities Entities = new BaseManageEntities())
159: {
160: var obj = Entities.CreateObjectSet<T>();
161: obj.AddObject(entity);
162: return Entities.SaveChanges() > 0;
163: }
164: }
165: /// <summary>
166: /// 更新Entity(注意这里使用的傻瓜式更新,可能性能略低)
167: /// </summary>
168: /// <param name="model"></param>
169: /// <returns></returns>
170: public virtual bool Update(T entity)
171: {
172: using (BaseManageEntities Entities = new BaseManageEntities())
173: {
174: var obj = Entities.CreateObjectSet<T>();
175: obj.Attach(entity);
176: Entities.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
177: return Entities.SaveChanges() > 0;
178: }
179:
180: }
181: /// <summary>
182: /// 删除Entity
183: /// </summary>
184: /// <param name="entity"></param>
185: /// <returns></returns>
186: public virtual bool Delete(T entity)
187: {
188: using (BaseManageEntities Entities = new BaseManageEntities())
189: {
190: var obj = Entities.CreateObjectSet<T>();
191:
192: if (entity != null)
193: {
194: obj.Attach(entity);
195: Entities.ObjectStateManager.ChangeObjectState(entity, EntityState.Deleted);
196:
197: obj.DeleteObject(entity);
198: return Entities.SaveChanges() > 0;
199:
200: }
201: return false;
202: }
203: }
204:
205: #endregion
206:
207:
208:
209: }
210: }
接下来我们的工作量就小了,我们可以看到成果了,我们接下来的实现,只需要继承上面这个BaseEFDao和IxxxDao的部分就可以很轻松的实现,子类的增删改查以及子类的扩展了.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using TZHSWEET.Entity;
6: using TZHSWEET.IDao;
7: namespace TZHSWEET.EFDao
8: {
9: public class FavoriteEFDao : BaseEFDao<tbFavorite>, IFavoriteDao<tbFavorite>
10: {
11:
12: }
13: }
大家可以看到继承了2个,一个是BaseEFDao父类,一个是IFavoriteDao接口,
BaseEFDao是实现EF的增删改查,IFavoriteDao实现了子类的扩展,比如子类需要加入
GetxxxByID之类的,当然我们在业务逻辑层一般只能通过IFavoriteDao调用此服务,而
这个继承体系保证了我们在实现增删改查的同时外放一个接口保证扩展性.
继承体系图:
这样我们的数据访问层,很轻松的实现了,基本上代码量非常少,增删改查部分几乎"0"代码,都是泛型的父类实现了.
今天就讲解到这里,接下来插播点当前有趣的实例部分:
界面友好,友好的名称远远比注释更好,<<重构>>这本书,让我学到太多太多,特别是细节的设计,更清晰.
可以参考,我的代码风格,可以看到我的进步非常大,我现在看到2-3个月以前的代码,简直都是<<重构>>这本书的反面教材.
当前的权限管理系统,设计了一个初步的模型,这里贴张小图:
参考了LigerUI,谢略的权限管理系统,吉日的权限管理数据库设计和N多日志,以及传说中的弦哥的Asp.Net大型项目实践系列教程,以及众多的资料,慢慢的我也会把这个写成一个系列.最后,写完这个教程,我会把代码传到公共网盘上面,不过由于现在代码持续改进,所以,就大家先看看思路.