2015-09-22 21 views
1

Я использую EF Core, и мне нужно иметь возможность выполнять поиск по нескольким столбцам, однако иногда элемент может быть нулевым.EF Core search multiple columns null error

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 Core. Вышеприведенный код бросает ссылку на объект, не установленную на экземпляр ошибки объекта.

ответ

3

Я добавил PredicateBuilderhere, чтобы включить метод расширения, называемый 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

это совершенно нормально, но это немного многословным. Если свойство имеет строку типа, вы можете использовать это выражение '(someProperty ??" ") .ToLower()'. Таким образом, вместо 'a.ADMSKey! = Null && a.ADMSKey.ToLower(). Содержит (search.ToLower())' вы можете писать '(a.ADMSKey ??" ") .ToLower(). Содержит (поиск) '. Кроме того, 'search' должен быть преобразован в нижнюю строку только один раз с помощью закрытия (in Where). – Hopeless

+0

@Hopeless хорошие идеи - я никогда не думал об использовании '(something ??" ")' вместо '! = Null' чеков! Можете ли вы разместить свой рефактор в качестве ответа? –

+0

@StaffordWilliams - это действительно необходимо, это всего лишь тривиальный совет. Также оно применяется только в том случае, если свойство является строкой (для другого типа мы всегда должны сначала проверять значение null перед использованием 'ToString()', как вы использовали). Я заметил, что некоторые свойства в вашем запросе выглядят действительно как числовые, кроме строки ('CoreCount',' PrimaryCurrentRatio', ...), но вы рассматриваете их как строки? – Hopeless