前奏:第一次写博客,记录一下学习和开发的过程。
现在写的是一个后台管理系统,有基本的权限功能,其他功能都可以扩展。用到的技术是 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类库的实现。