【问题标题】:linq function to handle : both fields equal or both null or empty要处理的 linq 函数:两个字段都相等或都为 null 或为空
【发布时间】:2012-10-24 08:18:24
【问题描述】:

您好,我有一个 linq 查询,我将一个对象与存储在我的数据库中的所有其他实体进行比较。名字和姓氏是必填字段,因此我不必检查是否为空。但就街道而言,我必须进行这些检查。

如果两个字段都是空字符串或空字符串或者它们相同,我想匹配。下面的 linq 查询工作正常。

但我在徘徊是不是有任何办法使它更具可读性。例如使用自定义函数,如 Bool FieldsAreEqualOrBothNullOrEmpty(r.street, request.street)

无法弄清楚如何做到这一点以及是否可能。

var same = 
   from r in db.Requests
   where r.firstName.ToLower() == request.firstName.ToLower()
      && r.lastName.ToLower() == request.lastName.ToLower()

      //Seems long to just compare two fields
      && ( string.IsNullOrEmpty(r.street) && string.IsNullOrEmpty(request.street) ) 
         || r.street.ToLower() == request.street.ToLower()

      select r;
return same;

【问题讨论】:

    标签: c# linq entity-framework


    【解决方案1】:

    我会简化:

    var same = 
       from r in db.Requests
       where r.firstName.ToLower() == request.firstName.ToLower()
          && r.lastName.ToLower() == request.lastName.ToLower()
       select r;
    
    if(string.IsNullOrEmpty(request.street)) {
        same = same.Where(r => string.IsNullOrEmpty(r.street));
    } else {
        string street = request.street.ToLower();
        same = same.Where(r => r.street.ToLower() == street);
    }
    

    这样做的好处是它使查询在每种情况下都保持简单。 如果您愿意,您可以对前两个使用类似的逻辑,并且它可以也可以移动到基于表达式的实用方法。未经测试:

    public static IQueryable<T> FieldsAreEqualOrBothNullOrEmpty<T>(
        this IQueryable<T> source,
        Expression<Func<T, string>> member, string value)
    {
        Expression body;
        if (string.IsNullOrEmpty(value))
        {
            body = Expression.Call(
                typeof(string), "IsNullOrEmpty", null, member.Body);
        }
        else
        {
            body = Expression.Equal(
                Expression.Call(member.Body, "ToLower", null),
                Expression.Constant(value.ToLower(), typeof(string)));
        }
    
        return source.Where(Expression.Lambda<Func<T,bool>>(
            body, member.Parameters));
    }
    

    然后:

    var same = db.Requests
               .FieldsAreEqualOrBothNullOrEmpty(x => x.firstName, request.firstName)
               .FieldsAreEqualOrBothNullOrEmpty(x => x.lastName, request.lastName)
               .FieldsAreEqualOrBothNullOrEmpty(x => x.street, request.street);
    

    【讨论】:

    • 非常感谢!基于表达式的方法是第一次尝试,效果很好!
    • 我在stackoverflow.com/questions/33315584/… 询问了一个关于此的问题,因为当数据库中有空值时我无法让它工作。
    【解决方案2】:

    您可以只调用String.Equals,但忽略大小写,使用适当的StringComparison

    string.equals(r.street, request.street, StringComparison.OrdinalIgnoreCase);
    

    将字符串转换为小写以进行比较是不好的做法,因为它不能可靠地在所有语言中工作,并且比使用忽略大小写的比较要慢。参见,例如,this answer

    【讨论】:

    • 取决于处理程序(在这种情况下为 EF)是否能够识别并正确处理它;每个处理程序和每个场景都不同。
    • 这与r.street = null && request.street = "" 的情况不匹配。为此,您需要类似:(r.street ?? "").Equals(request.street ?? "", StringComparison.OrdinalIgnoreCase);
    • 我试过这似乎是最简单的方法,但我的 sql server 数据库似乎不支持,因为排序规则,它会产生异常。
    • 还是谢谢你的回答:-)
    • @PaoloMoretti 你是对的,对不起。我误读了这个问题,并没有意识到他想将 null 和 empty 视为相同。
    【解决方案3】:

    如何在字符串IsEqualOrBothNullOrEmpty上创建扩展方法-

    public static class Extensions
    {
       public static bool IsEqualOrBothNullOrEmpty(this string firstValue,
                               string secondValue)
       {
          return string.IsNullOrEmpty(firstValue) &&
                   string.IsNullOrEmpty(secondValue)
                      || firstValue.ToLower() == secondValue.ToLower();
        }
    }
    

    并像这样在您的查询中使用 -

    var same = 
       from r in db.Requests
       where r.firstName.ToLower() == request.firstName.ToLower()
          && r.lastName.ToLower() == request.lastName.ToLower()
          && r.street.IsEqualOrBothNullOrEmpty(request.Street)
    
          select r;
    return same;
    

    【讨论】:

    • 这仅适用于 LINQ-to-Objects。问题状态(标签)实体框架。为此,您需要进行表达式重写。
    猜你喜欢
    • 2022-12-30
    • 1970-01-01
    • 2017-03-15
    • 2021-08-12
    • 1970-01-01
    • 2018-06-01
    • 2019-02-05
    • 2018-11-02
    • 1970-01-01
    相关资源
    最近更新 更多