zoukankan      html  css  js  c++  java
  • linq to sql之组装where条件下的'或'语句

    之前遇到过类似的需求,即前台传入几个过滤条件,后台动态组装where。

    例如,前台传入name='张三',age=10, 其余的字段,类似email,QQ之类的本次查询时不做过滤。

    用linq to sql来组装where语句非常方便。

    var f= db.Users.Where(x => true);
    if(!string.IsNullOrWhiteSpace(name))
        f= f.Where(x=>x.Name == name);
    if(age != null)
        f= f.Where(x=>x.Age == age);
    var data = f.ToList();

    今天碰到另一种情况。状态的多种可能性。用户的注册邮箱有多个状态(用int表示):未验证null,无效-1,有效0,退订-2,查看(>0的值)等。前台过滤时,可能勾选多个状态,例如未验证 或 有效 或 查看。用后台的where表示,就是:

    Where(x => x.EmailState == null || x.EmailState == 0 || x.EmailState > 0)

    问题出现了。这里有五种状态,每个状态有前台选中和未选中两种情况,组合的情况最多有2^5 = 32种。用32个if来解决这里的问题,不是不可以,只是代码会显得很笨重,而且扩展性很差,如果以后出现第六个、第七个状态......T_T...T_T

    首先想到的,能不能像上面的where组装那样实现。答案是不行。上面的where很明显是逻辑and运算。而这里应该是单个where情况下的or运算

    解决思路:用Func<Users,bool>来表示每一个邮箱状态对应的过滤语句。对勾选的每一个状态,对它们的过滤语句执行'||'运算。

    filter1(x) || filter2(x) || filter3(x)...

    代码方案一:

    Func<Users, bool> filter = x => false;
    if (chkEmailUnverify.Checked) filter = x => filter(x) || x.SendMail == null;
    if (chkEmailUnsubscribe.Checked) filter = x => filter(x) || x.SendMail == -2;
    if (chkEmailInvalid.Checked) filter = x => filter(x) || x.SendMail == -1;
    if (chkEmailValid.Checked) filter = x => filter(x) || x.SendMail == 0;
    if (chkEmailOpen.Checked) filter = x => filter(x) || (x.SendMail.HasValue && x.SendMail.Value > 0);

    对勾选的每一个状态,在之前的Func<Users,bool>基础上执行||运算。理论上来讲应该行得通,但是实际上调试的时候发现,只要超过两个勾选,就会报错:

    提示堆栈溢出。呃...对这类问题一直比较怵,对clr不了解。只能做猜测:因为filter本身就是代理,而代理的执行有延迟的特性,所以这里filter = x => filter(x)...可能会出现无限向下发展的情况。寻求曲线解决。

    代码方案二:

    Func<Users, bool> filter = x => true;
    List<Func<int?, bool>> list = new List<Func<int?, bool>>() { x => false };
    if (chkEmailUnverify.Checked) list.Add(x => x == null);
    if (chkEmailValid.Checked) list.Add(x => x == 0);
    if (chkEmailOpen.Checked) list.Add(x => x > 0);
    if (chkEmailUnsubscribe.Checked) list.Add(x => x == -2);
    if (chkEmailInvalid.Checked) list.Add(x => x == -1);
    
    filter = x => list.Select(c => c(x.SendMail)).Aggregate((a, b) => a || b);

    好吧,我承认只是在之前的那个思路基础上加了一个外壳。壳的主要思想是避免出现filter = x => filter(x) || x.Shield == 'value'。

    可能上面的考虑有些道理,这次的方案通过了编译,也取得了我要的结果。大功告成~o(∩_∩)o 

    调用时的代码:

    var f= db.Users.Where(filter);

    如有错误,欢迎留言指导。

    为MH370祈福~

  • 相关阅读:
    hdoj 3376,2686 Matrix Again 【最小费用最大流】
    Trustie站点代码托管使用指南
    POJ 2442 Sequence(堆的使用练习)
    猛犸机器学习开发实践
    关于《金字塔原理》的主要内容
    实战案例:如何快速打造1000万+播放量的抖音网红?
    【限时特惠】网易云易盾验证码全线95折!智能无感知、滑动拼图、点选验证-7天免费体验!
    当GDPR来敲门,中国互联网企业该如何应对?
    H5活动产品设计指南基础版
    Box(视图组件)如何在多个页面不同视觉规范下的复用
  • 原文地址:https://www.cnblogs.com/icyJ/p/sqlWhere.html
Copyright © 2011-2022 走看看