EF 结合IOC
接口层

public interface IBaseService : IDisposable//是为了释放Context { #region Query /// <summary> /// 根据id查询实体 /// </summary> /// <param name="id"></param> /// <returns></returns> T Find<T>(int id) where T : class; /// <summary> /// 提供对单表的查询 /// </summary> /// <returns>IQueryable类型集合</returns> [Obsolete("尽量避免使用,using 带表达式目录树的 代替")] 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; #endregion #region Add /// <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> IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class; #endregion #region Update /// <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; #endregion #region Delete /// <summary> /// 根据主键删除数据,即时Commit /// </summary> /// <param name="t"></param> void Delete<T>(int Id) where T : class; /// <su+mary> /// 删除数据,即时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; #endregion #region Other /// <summary> /// 立即保存全部修改 /// 把增/删的savechange给放到这里,是为了保证事务的 /// </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; #endregion }

public interface IUserCompanyService : IBaseService { void UpdateLastLogin(User user); bool RemoveCompanyAndUser(Company company); }
实现层

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 #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> [Obsolete("尽量避免使用,using 带表达式目录树的代替")] 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 #region Insert /// <summary> /// 即使保存 不需要再Commit /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> public T Insert<T>(T t) where T : class { this.Context.Set<T>().Add(t); this.Commit();//写在这里 就不需要单独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; } #endregion #region Update /// <summary> /// 是没有实现查询,直接更新的,需要Attach和State /// /// 如果是已经在context,只能再封装一个(在具体的service) /// </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(); } #endregion #region Delete /// <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(); } #endregion #region Other 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(); } } #endregion }

public class UserCompanyService : BaseService, IUserCompanyService { public UserCompanyService(DbContext context) : base(context) { } public void UpdateLastLogin(User user) { User userDB = base.Find<User>(user.Id); userDB.LastLoginTime = DateTime.Now; this.Commit(); } public bool RemoveCompanyAndUser(Company company) { return true; } }
引入IOC容器Untiy(unity可以做aop扩展)
配置文件里面做好 配置依赖关系及 aop扩展方法

<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="ruanmouContainer"> <extension type="Interception"/> <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Ruanmou.EF.Model.JDDbContext, Ruanmou.EF.Model"/> <register type="Ruanmou.Bussiness.Interface.IUserCompanyService,Ruanmou.Bussiness.Interface" mapTo="Ruanmou.Bussiness.Service.UserCompanyService, Ruanmou.Bussiness.Service"> <interceptor type="InterfaceInterceptor"/> <interceptionBehavior type="Ruanmou.Project.AOP.LogBeforeBehavior, Ruanmou.Project"/> <interceptionBehavior type="Ruanmou.Project.AOP.LogAfterBehavior, Ruanmou.Project"/> </register> </container> <container name="ruanmouContainerGeneric"> <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="Ruanmou.EF.Model.JDDbContext, Ruanmou.EF.Model"/> <register type="Ruanmou.Bussiness.Interface.IBaseService`1,Ruanmou.Bussiness.Interface" mapTo="Ruanmou.Bussiness.Service.BaseService`1, Ruanmou.Bussiness.Service"/> <register type="Ruanmou.Bussiness.Interface.ICategoryService,Ruanmou.Bussiness.Interface" mapTo="Ruanmou.Bussiness.Service.CategoryService, Ruanmou.Bussiness.Service"/> <register type="Ruanmou.Bussiness.Interface.ICommodityService,Ruanmou.Bussiness.Interface" mapTo="Ruanmou.Bussiness.Service.CommodityService, Ruanmou.Bussiness.Service"/> </container> </containers> </unity> </configuration>

public class LogAfterBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine($"{input.MethodBase.Name} LogAfterBehavior..Start."); foreach (var item in input.Inputs) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item)); } Console.WriteLine($"{input.MethodBase.Name} LogAfterBehavior.. End."); return methodReturn; } public bool WillExecute { get { return true; } } }

/// <summary> /// 不需要特性 /// </summary> public class LogBeforeBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { //Session Console.WriteLine($"{input.MethodBase.Name} LogBeforeBehavior..Start."); foreach (ParameterInfo item in input.Inputs) { Console.WriteLine($"{item.Name}:{Newtonsoft.Json.JsonConvert.SerializeObject(item)}" ); } Console.WriteLine($"{input.MethodBase.Name} LogBeforeBehavior.. End."); return getNext().Invoke(input, getNext); } public bool WillExecute { get { return true; } } }
创建unity容器,实例化
IUnityContainer container = ContainerFactory.GetContainer(); using (IUserCompanyService iUserCompanyService = container.Resolve<IUserCompanyService>()) { User user = iUserCompanyService.Find<User>(12); Company company = iUserCompanyService.Find<Company>(23); }
/// <summary> /// 容器的工厂,单例容器构造 /// </summary> public class ContainerFactory { private static IUnityContainer container = null; static ContainerFactory() { ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); container = new UnityContainer(); section.Configure(container, "ruanmouContainer"); } public static IUnityContainer GetContainer() { return container; } }
关于Service的问题
DbContext dbContext = new JDDbContext(); using (IUserService iUserService = new UserService(dbContext)) { User user = iUserService.Find<User>(123); //.... } using (ICompanyService iCompanyService = new CompanyService(new JDDbContext())) { Company company = iCompanyService.Find<Company>(123); //.... } //1 每张表都来一个Service? //需要join怎么办? 还有一个操作删除公司+用户 更新公司+用户 //这是业务逻辑,不应该在上端写的,应该在service using (IUserService iUserService = new UserService(new JDDbContext())) using (ICompanyService iCompanyService = new CompanyService(new JDDbContext())) { var result = from u in iUserService.Set<User>() join c in iCompanyService.Set<Company>() on u.CompanyId equals c.Id where u.Id > 100 select u;//这是错的 不同的上下文 } //2 单表单Service很多时候无法满足业务的需求,业务经常是跨表的 //所以在封装Service时,需要划分边界,完成组合。一个Service完成一个有机整体的全部操作 using (IUserCompanyService iUserCompanyService = new UserCompanyService(new JDDbContext())) { User user = iUserCompanyService.Find<User>(123); Company company = iUserCompanyService.Find<Company>(123); iUserCompanyService.UpdateLastLogin(user); iUserCompanyService.RemoveCompanyAndUser(company); } //难就难在怎么划分边界?! 根据项目的实际情况, //1 主外键关系一般在一个Service //2 Mapping式一般也可以放在一起 //3 单表单Service不算错比如日志 //频繁互动的 可以考虑合并一下 //上端难免还是要多个Service(多个context)共同操作,不要Join!事务UnitOfWork---TranscationScope UnitOfWork.Invoke(() => { using (IUserCompanyService iUserCompanyService = new UserCompanyService(new JDDbContext())) { //增删改 } });
public class UnitOfWork { public static void Invoke(Action action) { TransactionScope transaction = null; try { transaction = new TransactionScope(); action.Invoke(); transaction.Complete(); } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } } }
付费内容,请联系本人QQ:1002453261
本文来自博客园,作者:明志德道,转载请注明原文链接:https://www.cnblogs.com/for-easy-fast/articles/12530718.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析