前奏:第一次写博客,记录一下学习和开发的过程。
现在写的是一个后台管理系统,有基本的权限功能,其他功能都可以扩展。用到的技术是 asp.net mvc5,web api 2,entityframework,autofac,easyui等。
先来上个解决方案的图:
01-ZY.Web.MVC:是页面的展示,由于用了web api 所以在mvc里面没有做数据的操作。mvc里面主要有权限的判断,controller里面也没有太多的逻辑处理。
02-ZY.Web.Api:这里用到了web api。web api的好处是可以多平台调用,前后端可以分别开发,很好的分离了前后端的开发工作。
03-ZY.Identity:这里面主要是权限的判断,用到了asp.net identity。
04-ZY.Core:这个是项目的核心类库,包含了autofac,缓存,仓储接口,实体基类,扩展方法等,后续会详细的讲讲。
05-ZY.Repositories.EntityFramework:这个就是EntityFramework仓储的实现。
06-ZY.Model:这个就是实体类库。
在看一下运行的效果图片:
1:账号管理界面
2:编辑管理员 角色是多角色。
3:管理员选中角色,多角色选择,查找带回控件
4.设置菜单权限界面
5.角色管理 角色管理是在行内编辑
6.设置角色权限
7.菜单管理
8.设置菜单需要的按钮权限
再贴一些代码吧:
仓储接口
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using ZY.Core.Entities; namespace ZY.Core.Repositories { /// <summary> /// 仓储接口 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <typeparam name="TKey"></typeparam> public interface IRepository<TEntity, TKey> : IDependency where TEntity : IEntity<TKey> { IQueryable<TEntity> Entities { get; } #region 同步添加方法 /// <summary> /// 添加实体对象 /// </summary> /// <param name="entity"></param> void Insert(TEntity entity); /// <summary> /// 批量添加实体对象 /// </summary> /// <param name="entitys"></param> void Insert(IEnumerable<TEntity> entitys); #endregion #region 同步删除方法 /// <summary> /// 删除对象 /// </summary> /// <param name="entity"></param> void Remove(TEntity entity); /// <summary> /// 根据主键删除 /// </summary> /// <param name="key"></param> void Remove(TKey key); /// <summary> /// 根据条件删除 /// </summary> /// <param name="predicate"></param> void Remove(Expression<Func<TEntity, bool>> predicate); /// <summary> /// 批量删除对象 /// </summary> /// <param name="entitys"></param> void Remove(IEnumerable<TEntity> entitys); /// <summary> /// 根据主键批量删除 /// </summary> /// <param name="keys"></param> void Remove(IEnumerable<TKey> keys); #endregion #region 同步修改方法 /// <summary> /// 修改对象实体 /// </summary> /// <param name="entity"></param> void Update(TEntity entity); #endregion #region 同步判断方法 /// <summary> /// 根据主键判断实体是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> bool Exists(TKey key); /// <summary> /// 根据添加判断是否存在 /// </summary> /// <param name="predicate"></param> /// <returns></returns> bool Exists(Expression<Func<TEntity, bool>> predicate); #endregion #region 同步查询单条 /// <summary> /// 根据主键查询 /// </summary> /// <param name="key"></param> /// <returns></returns> TEntity GetByKey(TKey key); /// <summary> /// 根据条件获取单条记录 /// </summary> /// <param name="predicate"></param> /// <returns></returns> TEntity FirstOfDefault(Expression<Func<TEntity, bool>> predicate); #endregion #region 同步查询列表 /// <summary> /// 根据条件获取数据列表 /// </summary> /// <param name="predicate"></param> /// <returns></returns> IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate); #endregion #region 异步添加方法 /// <summary> /// 添加实体对象 /// </summary> /// <param name="entity"></param> Task<TEntity> InsertAsync(TEntity entity); /// <summary> /// 批量添加实体对象 /// </summary> /// <param name="entitys"></param> Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> entitys); #endregion #region 异步修改方法 /// <summary> /// 修改对象实体 /// </summary> /// <param name="entity"></param> Task<TEntity> UpdateAsync(TEntity entity); #endregion #region 异步判断方法 /// <summary> /// 根据主键判断实体是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> Task<bool> ExistsAsync(TKey key); /// <summary> /// 根据添加判断是否存在 /// </summary> /// <param name="predicate"></param> /// <returns></returns> Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate); #endregion #region 异步查询单条 /// <summary> /// 根据主键查询 /// </summary> /// <param name="key"></param> /// <returns></returns> Task<TEntity> GetByKeyAsync(TKey key); /// <summary> /// 根据条件获取单条记录 /// </summary> /// <param name="predicate"></param> /// <returns></returns> Task<TEntity> FirstOfDefaultAsync(Expression<Func<TEntity, bool>> predicate); #endregion #region 异步查询列表 /// <summary> /// 查询全部数据 /// </summary> /// <returns></returns> Task<List<TEntity>> GetAllAsync(); /// <summary> /// 根据条件获取数据列表 /// </summary> /// <param name="predicate"></param> /// <returns></returns> Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> predicate); #endregion #region 同步sql查询 /// <summary> /// 根据sql查询 /// </summary> /// <param name="query"></param> /// <param name="parameters"></param> /// <returns></returns> IEnumerable<TEntity> SqlQuery(string sql, params object[] parameters); #endregion } }
仓储的具体实现:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Data.Entity; using ZY.Core.Repositories; using ZY.Core.Entities; using System.Linq.Expressions; namespace ZY.Repositories.EntityFramework { /// <summary> /// EntityFramework 仓储 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <typeparam name="TKey"></typeparam> public class Repository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey> { protected DbContext _dbContext; protected IDbSet<TEntity> _dbSet; /// <summary> /// 构造函数 /// </summary> /// <param name="dbContext"></param> public Repository(DbContext dbContext) { _dbContext = dbContext; _dbSet = dbContext.Set<TEntity>(); } /// <summary> /// 全部实体对象 /// </summary> public IQueryable<TEntity> Entities { get { return _dbSet.AsQueryable(); } } #region 同步添加方法 /// <summary> /// 添加实体对象 /// </summary> /// <param name="entity"></param> public virtual void Insert(TEntity entity) { _dbSet.Add(entity); } /// <summary> /// 批量添加实体对象 /// </summary> /// <param name="entitys"></param> public virtual void Insert(IEnumerable<TEntity> entities) { _dbContext.Set<TEntity>().AddRange(entities); } #endregion #region 同步删除方法 /// <summary> /// 删除对象实体 /// </summary> /// <param name="entity"></param> public virtual void Remove(TEntity entity) { _dbSet.Remove(entity); } /// <summary> /// 根据主键删除实体 /// </summary> /// <param name="key"></param> public virtual void Remove(TKey key) { var entity = GetByKey(key); if (entity == null) return; Remove(entity); } /// <summary> /// 删除对象列表 /// </summary> /// <param name="entities"></param> public virtual void Remove(IEnumerable<TEntity> entities) { if (entities == null) return; if (!entities.Any()) return; _dbContext.Set<TEntity>().RemoveRange(entities); } /// <summary> /// 根据条件删除 /// </summary> /// <param name="predicate"></param> public virtual void Remove(Expression<Func<TEntity, bool>> predicate) { var entities = _dbSet.Where(predicate); Remove(entities); } /// <summary> /// 根据主键列表删除 /// </summary> /// <param name="keys"></param> public virtual void Remove(IEnumerable<TKey> keys) { if (keys == null) return; Remove(Query(t => keys.Contains(t.Id))); } #endregion #region 同步修改方法 /// <summary> /// 修改对象实体 /// </summary> /// <param name="entity"></param> public virtual void Update(TEntity entity) { _dbContext.Entry(entity).State = EntityState.Modified; } #endregion #region 同步判断方法 /// <summary> /// 判断主键是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> public virtual bool Exists(TKey key) { return GetByKey(key) == null ? false : true; } /// <summary> /// 根据条件判断对象是否存在 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual bool Exists(Expression<Func<TEntity, bool>> predicate) { return Query(predicate).Any(); } #endregion #region 同步查询单条 /// <summary> /// 根据主键获取对象 /// </summary> /// <param name="key"></param> /// <returns></returns> public virtual TEntity GetByKey(TKey key) { return _dbContext.Set<TEntity>().Find(key); } /// <summary> /// 获取单个实体 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual TEntity FirstOfDefault(Expression<Func<TEntity, bool>> predicate) { return Query(predicate).FirstOrDefault(); } #endregion #region 同步查询列表 /// <summary> /// 根据条件查询 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate) { return _dbSet.Where(predicate); } #endregion #region 异步添加方法 /// <summary> /// 添加实体对象 /// </summary> /// <param name="entity"></param> public virtual Task<TEntity> InsertAsync(TEntity entity) { return Task.FromResult(_dbSet.Add(entity)); } /// <summary> /// 批量添加实体对象 /// </summary> /// <param name="entitys"></param> public virtual Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> entities) { return Task.FromResult(_dbContext.Set<TEntity>().AddRange(entities)); } #endregion #region 同步修改方法 /// <summary> /// 修改对象实体 /// </summary> /// <param name="entity"></param> public virtual Task<TEntity> UpdateAsync(TEntity entity) { _dbContext.Entry(entity).State = EntityState.Modified; return Task.FromResult(entity); } #endregion #region 异步判断方法 /// <summary> /// 判断主键是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> public virtual async Task<bool> ExistsAsync(TKey key) { return await GetByKeyAsync(key) == null ? false : true; } /// <summary> /// 根据条件判断对象是否存在 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual async Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate) { return await Query(predicate).AnyAsync(); } #endregion #region 异步查询单条 /// <summary> /// 根据主键获取对象 /// </summary> /// <param name="key"></param> /// <returns></returns> public virtual async Task<TEntity> GetByKeyAsync(TKey key) { return await _dbContext.Set<TEntity>().FindAsync(key); } /// <summary> /// 获取单个实体 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual async Task<TEntity> FirstOfDefaultAsync(Expression<Func<TEntity, bool>> predicate) { return await Query(predicate).FirstOrDefaultAsync(); } #endregion #region 异步查询列表 /// <summary> /// 查询全部数据 /// </summary> /// <returns></returns> public virtual async Task<List<TEntity>> GetAllAsync() { return await _dbSet.ToListAsync(); } /// <summary> /// 根据条件查询 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public virtual async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> predicate) { return await _dbSet.Where(predicate).ToListAsync(); } #endregion #region 同步sql方法 /// <summary> /// 根据sql查询 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public IEnumerable<TEntity> SqlQuery(string sql, params object[] parameters) { return _dbContext.Database.SqlQuery<TEntity>(sql, parameters); } #endregion } }
关于Repository的具体实现思路,博客园里面有很多文章了,这里就不详细说明了。
IUnitOfWork 考虑到可能会执行单独的存储过程,所以在UnitOfWork里面加了对存储过程的支持
using System; using System.Data; using System.Threading.Tasks; namespace ZY.Core.Repositories { /// <summary> /// 业务单元操作接口 /// </summary> public interface IUnitOfWork: IDependency, IDisposable { /// <summary> /// 提交 /// </summary> /// <returns></returns> void Commit(); /// <summary> /// 异步提交 /// </summary> /// <returns></returns> Task CommitAsync(); /// <summary> /// 同步 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> int ExecuteSqlCommand(string sql, params object[] parameters); /// <summary> /// 异步执行SQL语句 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters); /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <returns></returns> DataSet QueryProcedure(string storedProcName); /// <summary> /// 执行存储过程 带参数 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <param name="parameters">参数</param> /// <returns></returns> DataSet QueryProcedure(string storedProcName, IDataParameter[] parameters); /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <param name="parameters">参数</param> /// <returns>存储过程返回值</returns> int RunProcedure(string storedProcName, IDataParameter[] parameters); /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <param name="parameters">参数</param> /// <returns></returns> int RunProcedure(string storedProcName); } }
UnitOfWork的具体实现
using System; using System.Data; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.Validation; using System.Data.SqlClient; using System.Text; using System.Threading.Tasks; using ZY.Core.Logging; using ZY.Core.Repositories; namespace ZY.Repositories.EntityFramework { /// <summary> /// 工作单元 /// </summary> public class UnitOfWork : IUnitOfWork { private DbContext _dbContext; //数据库上下文对象 private readonly ILog log; //日志接口 public UnitOfWork(DbContext dbContext) { _dbContext = dbContext; log = new Log(); } /// <summary> /// 提交 /// </summary> /// <returns></returns> public void Commit() { try { try { _dbContext.SaveChanges(); } catch (DbEntityValidationException exception) { throw new DataException("保存数据时,数据验证引发异常--", exception); } } catch (DbUpdateException ex) { throw new DataException("保存数据更改时引发异常--", ex); } } /// <summary> /// 异步提交 /// </summary> /// <returns></returns> public async Task CommitAsync() { try { try { await _dbContext.SaveChangesAsync(); } catch (DbEntityValidationException exception) { throw new DataException("保存数据时,数据验证引发异常--", exception); } } catch (DbUpdateException ex) { throw new DataException("保存数据更改时引发异常--",ex); } } /// <summary> /// 异步 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public async Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters) { return await _dbContext.Database.ExecuteSqlCommandAsync(sql, parameters); } /// <summary> /// 同步 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public int ExecuteSqlCommand(string sql, params object[] parameters) { return _dbContext.Database.ExecuteSqlCommand(sql, parameters); } /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <param name="parameters">参数</param> /// <returns></returns> public DataSet QueryProcedure(string storedProcName, IDataParameter[] parameters) { using (SqlConnection connection = new SqlConnection(_dbContext.Database.Connection.ConnectionString)) { try { DataSet dataSet = new DataSet(); connection.Open(); SqlDataAdapter sqlDA = new SqlDataAdapter(); sqlDA.SelectCommand = BuildQueryCommand(connection, storedProcName, parameters); sqlDA.Fill(dataSet); connection.Close(); return dataSet; } catch (Exception exception) { string error = string.Format("执行存储过程 名称:{0} 参数 {1}", storedProcName, GetParamterValue(parameters)); log.Error(error, exception); throw new Exception(error, exception); } } } /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <returns></returns> public DataSet QueryProcedure(string storedProcName) { using (SqlConnection connection = new SqlConnection(_dbContext.Database.Connection.ConnectionString)) { try { DataSet dataSet = new DataSet(); connection.Open(); SqlDataAdapter sqlDA = new SqlDataAdapter(); SqlCommand command = new SqlCommand(storedProcName, connection); command.CommandType = CommandType.StoredProcedure; sqlDA.SelectCommand = command; sqlDA.Fill(dataSet); connection.Close(); return dataSet; } catch (Exception exception) { string error = string.Format("执行存储过程 名称:{0}", storedProcName); log.Error(error, exception); throw new Exception(error, exception); } } } /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程名称</param> /// <param name="parameters">参数</param> /// <returns>存储过程返回值</returns> public int RunProcedure(string storedProcName, IDataParameter[] parameters) { using (SqlConnection connection = new SqlConnection(_dbContext.Database.Connection.ConnectionString)) { try { connection.Open(); SqlCommand command = BuildQueryCommand(connection, storedProcName, parameters); SqlParameter resultParam = new SqlParameter(); //构建存储过程返回值 resultParam.Direction = ParameterDirection.ReturnValue; command.Parameters.Add(resultParam); command.ExecuteNonQuery(); connection.Close(); return (int)resultParam.Value; } catch (Exception exception) { string error = string.Format("执行存储过程 名称:{0} 参数 {1}", storedProcName, GetParamterValue(parameters)); log.Error(error, exception); throw new Exception(error, exception); } } } /// <summary> /// 执行存储过程 /// </summary> /// <param name="storedProcName">存储过程</param> /// <returns>返回值</returns> public int RunProcedure(string storedProcName) { using (SqlConnection connection = (SqlConnection)_dbContext.Database.Connection) { try { connection.Open(); SqlCommand command = new SqlCommand(storedProcName, connection); command.CommandType = CommandType.StoredProcedure; SqlParameter resultParam = new SqlParameter(); //构建存储过程返回值 resultParam.Direction = ParameterDirection.ReturnValue; command.Parameters.Add(resultParam); command.ExecuteNonQuery(); connection.Close(); return (int)resultParam.Value; } catch (SqlException exception) { string error = string.Format("执行存储过程 名称:{0}", storedProcName); log.Error(error, exception); throw new Exception(error, exception); } } } /// <summary> /// 构建 SqlCommand 对象(用来返回一个结果集,而不是一个整数值) /// </summary> /// <param name="connection">数据库连接</param> /// <param name="storedProcName">存储过程名</param> /// <param name="parameters">存储过程参数</param> /// <returns>SqlCommand</returns> private SqlCommand BuildQueryCommand(SqlConnection connection, string storedProcName, IDataParameter[] parameters) { SqlCommand command = new SqlCommand(storedProcName, connection); command.CommandType = CommandType.StoredProcedure; foreach (SqlParameter parameter in parameters) { if (parameter != null) { // 检查未分配值的输出参数,将其分配以DBNull.Value. if ((parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Input) && (parameter.Value == null)) { parameter.Value = DBNull.Value; } command.Parameters.Add(parameter); } } return command; } /// <summary> /// 根据参数列表获取参数的名称和值,用于记录日志 /// </summary> /// <param name="parameters"></param> /// <returns></returns> private string GetParamterValue(IDataParameter[] parameters) { StringBuilder paramStr = new StringBuilder(); foreach (SqlParameter param in parameters) { paramStr.AppendFormat("{0} :{1}", param.ParameterName, param.Value); } return paramStr.ToString(); } //处理回收机制 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } //处理回收机制 private void Dispose(bool isdispose) { if (isdispose) { if (_dbContext != null) { _dbContext.Dispose(); _dbContext = null; } } } } }
这篇文章就暂时到这里,下一篇会介绍ZY.Repositories.EntityFramework类库的实现。