• 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祈福~

  • 相关阅读:
    git创建版本库
    DataSet的加密解密
    在InstallShield中加密字符串,在C#中解密
    asp.net后台长时间操作时,向前台输出“请等待"信息的方法
    DataSet的加密解密(续)
    XXTEA加密算法的InstallShield 脚本实现
    c#如何监视文件或者文件夹的变化
    wpf制作毛玻璃效果按钮的代码
    WPF中用于Path的Geometry MiniLanguage
    如何在非英文环境中正确显示数字
  • 原文地址:https://www.cnblogs.com/icyJ/p/sqlWhere.html
Copyright © 2020-2023  润新知