首页 > 代码库 > ASP.NET Mvc实用框架(一)Ioc、仓储模式和单元工作模式
ASP.NET Mvc实用框架(一)Ioc、仓储模式和单元工作模式
Framework.EF
首先看一下这个类库:
Extended文件夹存放的是EntityFramework.Extensions这个插件的源代码,没有别的原因,就是本人觉得这个插件挺好的,每次省的下载而已
IDependency:用于依赖注入的接口
IRepository和Repository:用于仓储模式
IUnitOfWork和UnitOfWork:用于单元工作模式
Page:分页实体
1、什么是依赖注入?
记得第一次接触依赖注入的时候是在我大二暑假自己出去实习的时候,当时带我的人让我看一看依赖注入这个东西,因为项目用到了,我愣是看了一个星期,各种熬夜、百度、问人,还没明白怎么回事?现在想想挺搞笑的。其实这个东西需要一定的项目经验理解起来会方便些,其实我们平时在研究问题的时候,当你实在解决不了的时候,不妨先记下来,有空的时候多看看,总有一天会豁然开朗的。扯远了。。。
其实依赖注入我跟喜欢把它当成控制反转,这样更贴切,为什么呢?举个例子:三层架构中的BLL层,我们通常定义一个接口层让它继承,在使用的时候,直接 接口申明 - BLL实例化,而控制反转的思想是将它们的顺序颠倒过来,也就是说我们不再关注接口到底是怎么实现的了,这样就实现了解耦合,在我看来这是一项伟大的创新。而实现控制反转这个思想当然是依赖注入容器,当然插件有很多,我用过Unity和Autofac,个人感觉还是第三方的Autofac强大,性能相对于Unity而言十分的明显
using System.Linq; using System.Reflection; using System.Web.Compilation; using System.Web.Mvc; using Autofac; using Autofac.Integration.Mvc; using Framework.EF; namespace Test.Web { public class AutofacConfig { /// <summary> /// 初始化 /// </summary> public static void Initialise() { var builder = RegisterService(); DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build())); } /// <summary> /// 注入实现 /// </summary> /// <returns></returns> private static ContainerBuilder RegisterService() { var builder = new ContainerBuilder(); var baseType = typeof(IDependency); //扫描IService和Service相关的程序集 var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>() .Where(m => m.FullName.Contains("Test")).ToList(); builder.RegisterControllers(assemblys.ToArray()); //自动注入 builder.RegisterAssemblyTypes(assemblys.ToArray()) .Where(t => baseType.IsAssignableFrom(t) && t != baseType) .AsImplementedInterfaces().InstancePerLifetimeScope(); return builder; } } }
2、什么是仓储模式?
关于这方面的介绍有很多,我说说我的理解,通常我们所用的ORM都会自己有一套CURD相关的方法,比方说EF中的dbcontext,NH中的session,其实我们会发现在仓储模式中又会定义一套CURD相关的方法,有的人会问:这TM的不是重复了吗?当时我也是这么想的,其实不然,如果你的ORM永远不可能变的话,那么你可以不用仓储模式,但是这种情况概率基本不可能发生,谁也无法保证你的领导脑袋会不会抽风,万一,就万一哪天需要更换底层的东西的呢?如果你使用了仓储模式的话,这样更换底层就十分的方便,只需要将仓储中的实现挨个重写一遍,这就是好处。
/* =============================================================== * 创 建 者:wms * 创建日期:2016/11/18 17:06:34 * 功能描述:仓储接口 * ===============================================================*/ namespace Framework.EF { using System; using System.Linq; using System.Linq.Expressions; /// <summary> /// 仓储接口 /// </summary> public interface IRepository<TEntity> : IDisposable where TEntity : class { #region 删除操作 /// <summary> /// 删除实体 /// </summary> /// <param name="entityToDelete">要删除的实体</param> void Delete(TEntity entityToDelete); /// <summary> /// 删除/批量删除 /// </summary> /// <param name="predicate">表达式</param> /// <returns></returns> int Delete(Expression<Func<TEntity, bool>> predicate); #endregion #region 更新操作 /// <summary> /// 批量更新 /// <code><![CDATA[ /// var db = new TrackerContext(); /// string emailDomain = "@test.com"; /// int count = db.Users.Update( /// u => u.Email.EndsWith(emailDomain), /// u => new User { IsApproved = false, LastActivityDate = DateTime.Now }); /// ]]></code> /// </summary> /// <param name="filterExpression">条件筛选表达式</param> /// <param name="updateExpression">更新表达式</param> int Update(Expression<Func<TEntity, bool>> filterExpression, Expression<Func<TEntity, TEntity>> updateExpression); #endregion #region 新增操作 /// <summary> /// 新增 /// </summary> /// <param name="entity">要新增的实体</param> TEntity Insert(TEntity entity); #endregion #region 查询操作 #region Count /// <summary> /// Count查询 /// </summary> /// <returns></returns> int Count(); /// <summary> /// Count查询 /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> int Count(Expression<Func<TEntity, bool>> predicate); #endregion #region 单个查询 /// <summary> /// 取查询结果中的第一条(为空抛异常) /// </summary> /// <returns></returns> TEntity First(); /// <summary> /// 取查询结果中的第一条(为空抛异常) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> TEntity First(Expression<Func<TEntity, bool>> predicate); /// <summary> /// 取查询结果中的第一条(为空返回默认值) /// </summary> /// <returns></returns> TEntity FirstOrDefault(); /// <summary> /// 取查询结果中的第一条(为空返回默认值) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate); /// <summary> /// 取一条数据(为空抛异常) /// </summary> /// <returns></returns> TEntity Single(); /// <summary> /// 取一条数据(为空抛异常) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> TEntity Single(Expression<Func<TEntity, bool>> predicate); /// <summary> /// 取一条数据(没有为空) /// </summary> /// <returns></returns> TEntity SingleOrDefault(); /// <summary> /// 取一条数据(没有为空) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate); #endregion /// <summary> /// 获取列表(延迟加载) /// </summary> /// <param name="predicate">表达式树</param> /// <returns></returns> IQueryable<TEntity> LoadEntities(Expression<Func<TEntity, bool>> predicate); #region 分页查询 /// <summary> /// 分页查询 /// </summary> /// <typeparam name="TKey">排序类型</typeparam> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">每页大小</param> /// <param name="isAsc">是否升序排列</param> /// <param name="keySelector">排序表达式</param> /// <returns></returns> IPage<TEntity> Page<TKey>(int pageIndex, int pageSize, bool isAsc, Expression<Func<TEntity, TKey>> keySelector); /// <summary> /// 分页查询 /// </summary> /// <typeparam name="TKey">排序类型</typeparam> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">每页大小</param> /// <param name="isAsc">是否升序排列</param> /// <param name="predicate">条件表达式</param> /// <param name="keySelector">排序表达式</param> /// <returns></returns> IPage<TEntity> Page<TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate, bool isAsc, Expression<Func<TEntity, TKey>> keySelector); #endregion #endregion /// <summary> /// 保存修改 /// </summary> /// <returns></returns> int SaveChanges(); } }
/* =============================================================== * 创 建 者:wms * 创建日期:2016/11/18 17:13:56 * 功能描述:仓储实现类 * ===============================================================*/ using EntityFramework.Extensions; using EntityFramework.Future; namespace Framework.EF { using System; using System.Data.Entity; using System.Linq; using System.Linq.Expressions; /// <summary> /// 仓储实现类 /// </summary> public class Repository<TEntity> : IRepository<TEntity> where TEntity : class { /// <summary> /// 上下文 /// </summary> protected DbContext dbContext; /// <summary> /// DbSet /// </summary> protected DbSet<TEntity> dbSet; /// <summary> /// 无参构造函数《用于单独的Service直接使用》 /// </summary> public Repository() { } /// <summary> /// 用于UnitOfWork /// </summary> /// <param name="dbContext">上下文</param> public Repository(DbContext dbContext) { this.dbContext = dbContext; this.dbSet = dbContext.Set<TEntity>(); } #region 删除操作 /// <summary> /// 删除操作 /// </summary> /// <param name="entityToDelete"></param> public virtual void Delete(TEntity entityToDelete) { if (dbContext.Entry(entityToDelete).State == EntityState.Detached) { dbSet.Attach(entityToDelete); } dbSet.Remove(entityToDelete); } /// <summary> /// 删除/批量删除 /// </summary> /// <param name="predicate">表达式</param> /// <returns></returns> public virtual int Delete(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.Delete(predicate); } #endregion #region 更新操作 /// <summary> /// 批量更新 /// <code><![CDATA[ /// var db = new TrackerContext(); /// string emailDomain = "@test.com"; /// int count = db.Users.Update( /// u => u.Email.EndsWith(emailDomain), /// u => new User { IsApproved = false, LastActivityDate = DateTime.Now }); /// ]]></code> /// </summary> /// <param name="filterExpression">条件筛选表达式</param> /// <param name="updateExpression">更新表达式</param> public virtual int Update(Expression<Func<TEntity, bool>> filterExpression, Expression<Func<TEntity, TEntity>> updateExpression) { return this.dbSet.Update(filterExpression, updateExpression); } #endregion #region 新增操作 /// <summary> /// 新增 /// </summary> /// <param name="entity">要新增的实体</param> public virtual TEntity Insert(TEntity entity) { return this.dbSet.Add(entity); } #endregion #region 查询操作 #region Count /// <summary> /// Count查询 /// </summary> /// <returns></returns> public virtual int Count() { return this.dbSet.Count(); } /// <summary> /// Count查询 /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> public virtual int Count(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.Count(); } #endregion #region 单个查询 /// <summary> /// 取查询结果中的第一条(为空抛异常) /// </summary> /// <returns></returns> public virtual TEntity First() { return this.dbSet.First(); } /// <summary> /// 取查询结果中的第一条(为空抛异常) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> public virtual TEntity First(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.First(predicate); } /// <summary> /// 取查询结果中的第一条(为空返回默认值) /// </summary> /// <returns></returns> public virtual TEntity FirstOrDefault() { return this.dbSet.FirstOrDefault(); } /// <summary> /// 取查询结果中的第一条(为空返回默认值) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> public virtual TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.FirstOrDefault(predicate); } /// <summary> /// 取一条数据(为空抛异常) /// </summary> /// <returns></returns> public virtual TEntity Single() { return this.dbSet.Single(); } /// <summary> /// 取一条数据(为空抛异常) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> public virtual TEntity Single(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.Single(predicate); } /// <summary> /// 取一条数据(没有为空) /// </summary> /// <returns></returns> public virtual TEntity SingleOrDefault() { return this.dbSet.SingleOrDefault(); } /// <summary> /// 取一条数据(没有为空) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> public virtual TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.SingleOrDefault(predicate); } #endregion /// <summary> /// 获取列表(延迟加载) /// </summary> /// <param name="predicate">表达式树</param> /// <returns></returns> public virtual IQueryable<TEntity> LoadEntities(Expression<Func<TEntity, bool>> predicate) { return this.dbSet.Where(predicate); } #region 分页查询 /// <summary> /// 分页查询 /// </summary> /// <typeparam name="TKey">排序类型</typeparam> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">每页大小</param> /// <param name="isAsc">是否升序排列</param> /// <param name="keySelector">排序表达式</param> /// <returns></returns> public virtual IPage<TEntity> Page<TKey>(int pageIndex, int pageSize, bool isAsc, Expression<Func<TEntity, TKey>> keySelector) { return this.Page(pageIndex, pageSize, null, isAsc, keySelector); } /// <summary> /// 分页查询 /// </summary> /// <typeparam name="TKey">排序类型</typeparam> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">每页大小</param> /// <param name="isAsc">是否升序排列</param> /// <param name="predicate">条件表达式</param> /// <param name="keySelector">排序表达式</param> /// <returns></returns> public virtual IPage<TEntity> Page<TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate, bool isAsc, Expression<Func<TEntity, TKey>> keySelector) { if (pageIndex <= 0 && pageSize <= 0) { throw new Exception("pageIndex或pageSize不能小于等于0!"); } IPage<TEntity> page = new Page<TEntity>() { PageIndex = pageIndex, PageSize = pageSize }; int skip = (pageIndex - 1) * pageSize; if (predicate == null) { FutureCount fcount = this.dbSet.FutureCount(); FutureQuery<TEntity> futureQuery = isAsc ? this.dbSet.OrderBy(keySelector).Skip(skip).Take(pageSize).Future() : this.dbSet.OrderByDescending(keySelector).Skip(skip).Take(pageSize).Future(); page.TotalItems = fcount.Value; page.Items = futureQuery.ToList(); page.TotalPages = page.TotalItems / pageSize; if ((page.TotalItems % pageSize) != 0) page.TotalPages++; } else { var queryable = this.dbSet.Where(predicate); FutureCount fcount = queryable.FutureCount(); FutureQuery<TEntity> futureQuery = isAsc ? queryable.OrderBy(keySelector).Skip(skip).Take(pageSize).Future() : queryable.OrderByDescending(keySelector).Skip(skip).Take(pageSize).Future(); page.TotalItems = fcount.Value; page.Items = futureQuery.ToList(); page.TotalPages = page.TotalItems / pageSize; if ((page.TotalItems % pageSize) != 0) page.TotalPages++; } return page; } #endregion #endregion /// <summary> /// 资源释放 /// </summary> public virtual void Dispose() { dbContext.Dispose(); } /// <summary> /// 保存修改 /// </summary> /// <returns></returns> public virtual int SaveChanges() { return this.dbContext.SaveChanges(); } } }
3、什么是单元工作模式?
其实就是统一资源,减少资源浪费而已,我们就拿EF来说,其实我发现有些人会在单元工作模式中定义了一些事务的操作方法,在我看来这是没有必要的,为什么呢?因为EF中的上下文本身就是具有事务性质的,我们只需要在单元工作模式中定义一个统一提交的方法即可,如下:
/* ============================================================================== * 创 建 者:wms * 创建日期:2016-11-18 16:55:25 * 功能描述:单元工作模式接口 * ==============================================================================*/ namespace Framework.EF { using System; /// <summary> /// 单元工作模式 /// </summary> public interface IUnitOfWork : IDisposable { /// <summary> /// 保存 /// </summary> void SaveChanges(); } }
/* ============================================================================== * 创 建 者:wms * 创建日期:2016-11-18 16:55:49 * 功能描述:单元工作模式 * ==============================================================================*/ namespace Framework.EF { using System; using System.Data.Entity; /// <summary> /// 单元工作模式 /// </summary> public abstract class UnitOfWork : IUnitOfWork { /// <summary> /// /// </summary> /// <param name="dbContext"></param> protected UnitOfWork(DbContext dbContext) { this.DbContext = dbContext; } /// <summary> /// 共用上下文 /// </summary> public DbContext DbContext { get; set; } /// <summary> /// 保存 /// </summary> public void SaveChanges() { this.DbContext.SaveChanges(); } private bool disposed = false; /// <summary> /// 资源释放 /// </summary> /// <param name="disposing"></param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { this.DbContext.Dispose(); } } this.disposed = true; } /// <summary> /// 资源释放 /// </summary> public void Dispose() { GC.SuppressFinalize(this); } } }
本系列完成之后附上源代码
ASP.NET Mvc实用框架(一)Ioc、仓储模式和单元工作模式