先来看一下我们的解决方案
我们建立Yubay.Models项目,
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Yubay.Models.Data { public class YubayDbContext : DbContext { public YubayDbContext() : base("YubayConnection") { } public DbSet<Category> Category { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.CreateIfNotExists(); base.OnModelCreating(modelBuilder); } } }
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Yubay.Models { [Table("Category")] public partial class Category { public int Id { get; set; } [StringLength(100)] public string Code { get; set; } [StringLength(100)] public string ParentCode { get; set; } public int? CategoryLevel { get; set; } [StringLength(50)] public string Name { get; set; } [StringLength(1000)] public string Url { get; set; } public int? State { get; set; } } }
接着再建立Yubay.Service项目
using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using Yubay.Core.Models; namespace Yubay.Service { public interface IBaseService : IDisposable { /// <summary> /// 根据id查询实体 /// </summary> /// <param name="id"></param> /// <returns></returns> T Find<T>(int id) where T : class; /// <summary> /// 提供对单表的查询, /// </summary> /// <returns>IQueryable类型集合</returns> IQueryable<T> Set<T>() where T : class; /// <summary> /// 查询 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="funcWhere"></param> /// <returns></returns> IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class; /// <summary> /// 分页查询 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="S"></typeparam> /// <param name="funcWhere"></param> /// <param name="pageSize"></param> /// <param name="pageIndex"></param> /// <param name="funcOrderby"></param> /// <param name="isAsc"></param> /// <returns></returns> PageResult<T> QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, S>> funcOrderby, bool isAsc = true) where T : class; /// <summary> /// 新增数据,即时Commit /// </summary> /// <param name="t"></param> /// <returns>返回带主键的实体</returns> T Insert<T>(T t) where T : class; /// <summary> /// 新增数据,即时Commit /// 多条sql 一个连接,事务插入 /// </summary> /// <param name="tList"></param> /// <returns>返回带主键的集合</returns> IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class; /// <summary> /// 更新数据,即时Commit /// </summary> /// <param name="t"></param> void Update<T>(T t) where T : class; /// <summary> /// 更新数据,即时Commit /// </summary> /// <param name="tList"></param> void Update<T>(IEnumerable<T> tList) where T : class; /// <summary> /// 根据主键删除数据,即时Commit /// </summary> /// <param name="t"></param> void Delete<T>(int Id) where T : class; /// <summary> /// 删除数据,即时Commit /// </summary> /// <param name="t"></param> void Delete<T>(T t) where T : class; /// <summary> /// 删除数据,即时Commit /// </summary> /// <param name="tList"></param> void Delete<T>(IEnumerable<T> tList) where T : class; /// <summary> /// 立即保存全部修改 /// </summary> void Commit(); /// <summary> /// 执行sql 返回集合 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class; /// <summary> /// 执行sql,无返回 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> void Excute<T>(string sql, SqlParameter[] parameters) where T : class; } }
using System; using System.Collections.Generic; using System.Data.Entity; using System.Data.SqlClient; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using Yubay.Core.Models; namespace Yubay.Service { public class BaseService : IBaseService { #region Identity protected DbContext Context { get; private set; } /// <summary> /// 构造函数注入 /// </summary> /// <param name="context"></param> public BaseService(DbContext context) { this.Context = context; } #endregion Identity public T Insert<T>(T t) where T : class { this.Context.Set<T>().Add(t); this.Commit(); return t; } public IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class { this.Context.Set<T>().AddRange(tList); this.Commit();//一个链接 多个sql return tList; } #region Query public T Find<T>(int id) where T : class { return this.Context.Set<T>().Find(id); } /// <summary> /// 不应该暴露给上端使用者 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public IQueryable<T> Set<T>() where T : class { return this.Context.Set<T>(); } /// <summary> /// 这才是合理的做法,上端给条件,这里查询 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="funcWhere"></param> /// <returns></returns> public IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class { return this.Context.Set<T>().Where<T>(funcWhere); } public PageResult<T> QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, S>> funcOrderby, bool isAsc = true) where T : class { var list = this.Set<T>(); if (funcWhere != null) { list = list.Where<T>(funcWhere); } if (isAsc) { list = list.OrderBy(funcOrderby); } else { list = list.OrderByDescending(funcOrderby); } PageResult<T> result = new PageResult<T>() { DataList = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(), PageIndex = pageIndex, PageSize = pageSize, TotalCount = this.Context.Set<T>().Count(funcWhere) }; return result; } #endregion /// <summary> /// 是没有实现查询,直接更新的 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> public void Update<T>(T t) where T : class { if (t == null) throw new Exception("t is null"); this.Context.Set<T>().Attach(t);//将数据附加到上下文,支持实体修改和新实体,重置为UnChanged this.Context.Entry<T>(t).State = EntityState.Modified; this.Commit();//保存 然后重置为UnChanged } public void Update<T>(IEnumerable<T> tList) where T : class { foreach (var t in tList) { this.Context.Set<T>().Attach(t); this.Context.Entry<T>(t).State = EntityState.Modified; } this.Commit(); } /// <summary> /// 先附加 再删除 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> public void Delete<T>(T t) where T : class { if (t == null) throw new Exception("t is null"); this.Context.Set<T>().Attach(t); this.Context.Set<T>().Remove(t); this.Commit(); } /// <summary> /// 还可以增加非即时commit版本的, /// 做成protected /// </summary> /// <typeparam name="T"></typeparam> /// <param name="Id"></param> public void Delete<T>(int Id) where T : class { T t = this.Find<T>(Id);//也可以附加 if (t == null) throw new Exception("t is null"); this.Context.Set<T>().Remove(t); this.Commit(); } public void Delete<T>(IEnumerable<T> tList) where T : class { foreach (var t in tList) { this.Context.Set<T>().Attach(t); } this.Context.Set<T>().RemoveRange(tList); this.Commit(); } public void Commit() { this.Context.SaveChanges(); } public IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class { return this.Context.Database.SqlQuery<T>(sql, parameters).AsQueryable(); } public void Excute<T>(string sql, SqlParameter[] parameters) where T : class { DbContextTransaction trans = null; try { trans = this.Context.Database.BeginTransaction(); this.Context.Database.ExecuteSqlCommand(sql, parameters); trans.Commit(); } catch (Exception ex) { if (trans != null) trans.Rollback(); throw ex; } } public virtual void Dispose() { if (this.Context != null) { this.Context.Dispose(); } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Yubay.Models; namespace Yubay.Service { public interface ICategoryService : IBaseService { #region Query /// <summary> /// 用code获取当前类及其全部子孙类别的id /// </summary> /// <param name="code"></param> /// <returns></returns> IEnumerable<int> GetDescendantsIdList(string code); /// <summary> /// 根据类别编码找子类别集合 找一级类用默认code root /// </summary> /// <param name="code"></param> /// <returns></returns> IEnumerable<Category> GetChildList(string code = "root"); /// <summary> /// 查询并缓存全部的类别数据 /// 类别数据一般是不变化的 /// </summary> /// <returns></returns> List<Category> CacheAllCategory(); #endregion Query } }
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; using Yubay.Core.Caching; using Yubay.Models; namespace Yubay.Service { public class CategoryService : BaseService, ICategoryService { #region Identity private DbSet<Category> _CategorySet = null; public CategoryService(DbContext dbContext) : base(dbContext) { this._CategorySet = base.Context.Set<Category>(); } #endregion Identity #region Query /// <summary> /// 用code获取当前类及其全部子孙类别的id /// </summary> /// <param name="code"></param> /// <returns></returns> public IEnumerable<int> GetDescendantsIdList(string code) { return this._CategorySet.Where(c => c.Code.StartsWith(code)).Select(c => c.Id); } /// <summary> /// 根据类别编码找子类别集合 找一级类用默认code root /// </summary> /// <param name="code"></param> /// <returns></returns> public IEnumerable<Category> GetChildList(string code = "root") { return this._CategorySet.Where(c => c.ParentCode.StartsWith(code)); } /// <summary> /// 查询并缓存全部数据 /// </summary> /// <returns></returns> public List<Category> CacheAllCategory() { return CacheManager.Get<List<Category>>("AllCategory", () => this._CategorySet.ToList()); } #endregion Query } }
接着再创建Yubay.Core项目,里面主要的两个类
using Microsoft.Practices.Unity.Configuration; using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Unity; namespace Yubay.Core.IOC { /// <summary> /// 依赖注入工厂 /// </summary> public class DIFactory { private static object _SyncHelper = new object(); private static Dictionary<string, IUnityContainer> _UnityContainerDictionary = new Dictionary<string, IUnityContainer>(); /// <summary> /// 根据containerName获取指定的container /// </summary> /// <param name="containerName">配置的containerName,默认为defaultContainer</param> /// <returns></returns> public static IUnityContainer GetContainer(string containerName = "unityContainer") { if (!_UnityContainerDictionary.ContainsKey(containerName)) { lock (_SyncHelper) { if (!_UnityContainerDictionary.ContainsKey(containerName)) { //配置UnityContainer IUnityContainer container = new UnityContainer(); ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "config\unity.config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); configSection.Configure(container, containerName); _UnityContainerDictionary.Add(containerName, container); } } } return _UnityContainerDictionary[containerName]; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Mvc; using System.Web.Routing; using Unity; namespace Yubay.Core.IOC { /// <summary> /// 自定义的控制器实例化工厂 /// </summary> public class UnityControllerFactory : DefaultControllerFactory { private IUnityContainer UnityContainer { get { return DIFactory.GetContainer(); } } /// <summary> /// 创建控制器对象 /// </summary> /// <param name="requestContext"></param> /// <param name="controllerType"></param> /// <returns></returns> protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (null == controllerType) { return null; } IController controller = (IController)this.UnityContainer.Resolve(controllerType); return controller; } /// <summary> /// 释放 /// </summary> /// <param name="controller"></param> public override void ReleaseController(IController controller) { //释放对象 base.ReleaseController(controller);// } } }
最后在MVC项目里面配置unity.config
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> </configSections> <unity> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/> <containers> <container name="unityContainer"> <extension type="Interception"/> <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Yubay.Models.Data.YubayDbContext, Yubay.Models"/> <register type="Yubay.Service.IBaseService,Yubay.Service" mapTo="Yubay.Service.BaseService, Yubay.Service"/> <register type="Yubay.Service.ICategoryService,Yubay.Service" mapTo="Yubay.Service.CategoryService, Yubay.Service"/> </container> <container name="unityContainerGeneric"> <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Yubay.Models.Data.YubayDbContext, Yubay.Models"/> <register type="Yubay.Service.IBaseService`1,Yubay.Service" mapTo="Yubay.Service.BaseService`1, Yubay.Service"/> <register type="Yubay.Service.ICategoryService,Ruanmou.Yubay.Service" mapTo="Yubay.Service.CategoryService, Yubay.Service"/> </container> </containers> </unity> </configuration>
那么这时候如何把Unity整合到MVC呢?我们知道http请求管道中,激活Controller的时候有一个DefaultControllerFactory,我们可以通过重写它的方法来实现,在Application_Start中使用下面的语句替换掉默认的DefaultControllerFactory。
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());//替换默认的控制器工厂
至此就将Unity整合到MVC中了。