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
    }
View Code
复制代码
复制代码
    public interface IUserCompanyService : IBaseService
    {
        void UpdateLastLogin(User user);

        bool RemoveCompanyAndUser(Company company);
    }
View Code
复制代码

实现层

复制代码
  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
    }
View Code
复制代码
复制代码
    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;
        }
       
    }
View Code
复制代码

引入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>
View Code
复制代码
复制代码
  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; }
        }
    }
View Code
复制代码
复制代码
 /// <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; }
        }
    }
View Code
复制代码

创建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;
            }
        }
    }
复制代码

 

posted @   明志德道  阅读(252)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示