通用弹出选择页面业务过滤示例

背景

  目前系统中,使用较多的通用选择包括:人员选择,品类选择,供应商选择等。采用的模式,基本上是点击按钮或者不可写的文本框。类似图:

其基本实现,主要是通过调用dialog加载人员选择/品类选择/供应商选择页面。

 

缺点分析

采用此方法可以满足大多数的应用场景,但是如果当对弹出里的数据进行初始过滤就会变得很麻烦,拿上图弹出页面“人员选择”举例:如果有个按钮,它的功能是弹出人员选择页面,但是它想要的数据源不是默认的数据源,现有页面的数据源是所有的人员,虽然提供了部分查询语句进行过滤,但是一旦业务需求只展示内部用户或者只显示某个特殊的人员,再或者这个页面是外部和内部都使用的页面,外面人员使用时看不到所有的用户,那么此页面会变得不使用。当然也有人说我们可以在取数据加上这些逻辑就可以了呀。但是随着需求越来越多,程序就会变成很难维护,并且臃肿不堪。更有甚至,光人员选择页面需要提供多个页面,或者多个数据源来维护。

 

解决办法

 

图解:

 

  1. 创建一个获取所有用户的方法
  2. 创建一个补充方法
  3. 取交集

要求:1和3是不可以变动的,不然就少了通用性,2是可以随时变动,2的变动会影响最终的结果

 

代码实现:

获取用户的代码

        /// <summary>
        /// 获取用户
        /// </summary>
        /// <param name="conditon"></param>
        /// <returns></returns>
        public string GetUserList(SelectUserParamDto conditon)
        {
            using (var dbContext = new Context())
            {
                var users = (from j in dbContext.T_User
                             where
                                 j.IsAdmin == conditon.IsAdmin &&
                                 j.IsSupplier == conditon.IsSupplier
                             select new SelectUserDto
                             {
                                 UserID = c.UserID,
                                 UserCode = c.UserCode,
                                 Name = c.Name,
                                 Mail = c.Mail,
                                 OrgName = IsCN ? b.OrgCName : b.OrgEName,
                                 PositionName = IsCN ? b.PositionCName : b.PositionEName,
                                 CreateTime = c.CreateTime,
                                 EnableDes = c.Enable == true ? Resource.PMOrg.PMOrg.Enable : Resource.PMOrg.PMOrg.Disabled
                             });

                if (!string.IsNullOrEmpty(conditon.Method))
                {
                    var otherMethod = Call(dbContext, conditon);
                    //关联新的人员
                    users = from a in users
                            join b in otherMethod on a.UserID equals b.UserId
                            select a;
                }
                return users
            }
        }

2.增加补充方法

public class CommonForCall
    {
        /// <summary>
        /// 获取跟供应商相关的发布人
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="conditon"></param>
        /// <returns></returns>
        public IQueryable<QueryResultDto> GetUsers(SMS_V40Context dbContext, SelectUserParamDto conditon)
        {
            if (conditon.CurrentUser.IsSupplier == true)
            {
                var currentUser = dbContext.T_User.FirstOrDefault(j => j.UserID == conditon.CurrentUser.UserID);
                if (currentUser == null) throw new Exception("非法用户");
                var info = from a in dbContext.T_SC_Scar
                    join b in dbContext.T_PM_User on a.Publisher equals b.UserID
                    where a.SupplierId == currentUser.SupplierID
                    select new QueryResultDto
                    {
                        UserId = b.UserID,
                        UserCode = b.UserCode
                    };
                return info;
            }
            else
            {
                var info = from a in dbContext.T_PM_User.Where(j => j.IsSupplier != true)
                    select new QueryResultDto
                    {
                        UserId = a.UserID,
                        UserCode = a.UserCode
                    };
                return info;
            }
        }
    }

3.通用方法调用

public class CommonCall
    {
        /// <summary>
        /// 动态调用传递的方法
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public static IQueryable<T1> Call<T1>(SMS_V40Context dbContext, ConditionDto condition)
        {
            var instance = new CommonForCall();
            var instType = instance.GetType();
            var dynamicMethod = new DynamicMethod("", typeof(IQueryable<T1>), new Type[] { instType, typeof(SMS_V40Context), typeof(ConditionDto) }, true);
            var stringMethod = instType.GetMethod(condition.Method, new Type[] { typeof(SMS_V40Context), typeof(ConditionDto) });
            if (stringMethod == null) throw new Exception("未发现需要调用的方法方法");
            var ilGen = dynamicMethod.GetILGenerator();//IL生成器
            //压参数到堆栈上
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldarg_1);
            ilGen.Emit(OpCodes.Ldarg_2);

            //调用方法
            ilGen.Emit(OpCodes.Callvirt, stringMethod);
            ilGen.Emit(OpCodes.Ret);//结束并返回值
            //生成委托
            var gan = (Func<SMS_V40Context, ConditionDto, IQueryable<T1>>)dynamicMethod.CreateDelegate(typeof(Func<SMS_V40Context, ConditionDto, IQueryable<T1>>), instance);
            //调用委托返回结果
            return gan(dbContext, condition);
        }
    }

 4.前台调用页面的时候需要传递一个Method的参数,用于告诉后端方法,此次调用的补充方法是哪个。所有的补充方法放入类CommonForCall中。

以上是整个实现,每次需要有特殊业务的时候,只需要在CommonForCall中创建一个特殊业务的方法,然后前台的Method参数置为创建的特殊业务方法名即可

posted @ 2020-07-10 16:52  小小的菜鸟程序员  阅读(275)  评论(0编辑  收藏  举报