2015-09-22 45 views
1

我正在使用EF核心,我需要能够在多个列上进行搜索,但是有时项目可能为空。EF核心搜索多列空错误

var myObject = _Context.CurrentTransformers.Where(a => 
    a.ID.ToString().Contains(search) || 
    a.ADMSKey.Contains(search) || 
    a.AccuracyClass.ToString().Contains(search) || 
    a.CoreCount.Contains(search) || 
    a.PrimaryCurrentRatio.Contains(search) || 
    a.SecondaryCurrentRatio.Contains(search) || 
    a.EOLXINIVVC.Contains(search)); 

我知道在以前的版本中,我可以使用UseCSharpNullComparisonBehavior但是我无法找到ContextOptions EF内线核心。上面的代码抛出一个对象引用未设置为对象错误的实例。

回答

3

我扩展了PredicateBuilder发布here以包含名为Search<T>的扩展方法。

你可以这样称呼它;

var myObject = _Context.CurrentTransformers.Search(search); 

代码

public static class PredicateBuilder 
{ 
    public static Expression<Func<T, bool>> True<T>() { return f => true; } 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 

    public static IQueryable<T> Search<T>(this IQueryable<T> self, string keyword) 
    { 
     var predicate = False<T>(); 
     var properties = typeof(T).GetTypeInfo().DeclaredProperties; 
     foreach (var propertyInfo in properties) 
     { 
      if (propertyInfo.GetGetMethod().IsVirtual) 
       continue; 

      var parameter = Expression.Parameter(typeof(T), "x"); 
      var property = Expression.Property(parameter, propertyInfo); 

      var propertyAsObject = Expression.Convert(property, typeof(object)); 
      var nullCheck = Expression.NotEqual(propertyAsObject, Expression.Constant(null, typeof(object))); 

      var propertyAsString = Expression.Call(property, "ToString", null, null); 
      var keywordExpression = Expression.Constant(keyword); 
      var contains = Expression.Call(propertyAsString, "Contains", null, keywordExpression); 

      var lambda = Expression.Lambda(Expression.AndAlso(nullCheck, contains), parameter); 

      predicate = predicate.Or((Expression<Func<T, bool>>)lambda); 
     } 
     return self.Where(predicate); 
    } 

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) 
    { 
     var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) 
    { 
     var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>> 
       (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); 
    } 
} 
+0

你是先生。这很好! –

0

我这样做:

var myObject = _Context.CurrentTransformers.Where(a => 
    a.ID.ToString().Contains(search) || 
    a.ADMSKey != null && a.ADMSKey.ToLower().Contains(search.ToLower()) || 
    a.AccuracyClass != null && a.AccuracyClass.ToString().ToLower().Contains(search.ToLower()) || 
    a.CoreCount != null && a.CoreCount.ToLower().Contains(search.ToLower()) || 
    a.PrimaryCurrentRatio != null && a.PrimaryCurrentRatio.ToLower().Contains(search.ToLower()) || 
    a.SecondaryCurrentRatio != null && a.SecondaryCurrentRatio.ToLower().Contains(search.ToLower()) || 
    a.EOLXINIVVC != null && a.EOLXINIVVC.ToLower().Contains(search.ToLower())); 

这工作,但就是脏或者是没事做?

+1

这是完全正常的,但它是一个有点冗长。如果属性的类型为string,则可以使用此表达式'(someProperty ??“”“).ToLower()'。因此,不用'a.ADMSKey!= null && a.ADMSKey.ToLower()。包含(search.ToLower())''您可以编写'(a.ADMSKey ??“”“).ToLower()。包含(搜索) '。此外,通过使用闭包(在Where中),'search'应该只转换为较低的字符串一次。 – Hopeless

+0

@Hopeless好主意 - 我从来没有想过使用'(something ??“”)''而不是'!= null'检查!你可以发布重构作为答案吗? –

+0

@Stafford威廉姆斯真的很有必要,这只是一个小小的提示。此外,它仅适用于属性是字符串的情况(对于其他类型,我们总是必须在使用'ToString()'之前先检查null)。我注意到查询中的一些属性看起来非常类似于数字,而不是字符串('CoreCount','PrimaryCurrentRatio',...),但将它们视为字符串? – Hopeless