Подтвердить что ты не робот

Создание общей функции предиката

Во-первых, я не уверен, какие условия использовать, чтобы задать этот вопрос, что, вероятно, поэтому я не нашел ответа от себя.

Итак, я работаю с Linq to SQL (С#,.Net 4), и я хочу получить список всех пользователей, которые соответствуют критериям, основы которых я бы сделал примерно так:

var users = DataContext.Users.Where(x => x.Criteria1 == "something");

но в этом случае есть несколько полей, которые я хочу сопоставить, все эти конкретные поля являются общей проверкой, и я хотел бы иметь возможность создавать функцию выделения, которую я могу использовать в любых моих пользовательских запросах проверьте этот матч.

Чтобы попытаться объяснить, что немного лучше дать пример: Допустим, у пользователя есть 5 флагов, и мне нужна общая проверка, чтобы увидеть, установлен ли какой-либо из этих флагов. Поэтому я мог бы написать свой запрос следующим образом:

var users = DataContext.Users.Where(x => x.Flag1 || x.Flag2 || x.Flag3 || x.Flag4 || x.Flag5);

Но то, что я хотел бы сделать, - это выделить "флажок флажка 5", чтобы я мог использовать его и в других запросах, в конечном итоге я хотел бы использовать что-то вроде:

var users = DataContext.Users.Where(x => x.Criteria1 == "something" && CheckForFlags(x));

Я пробовал это, имея такую ​​функцию:

static bool CheckForFlags(User user)
{
   return user.Flag1 || user.Flag2 || user.Flag3 || user.Flag4 || user.Flag5;
}

но я получаю сообщение об ошибке:

"Метод" Boolean CheckForFlags (Пользователь) "не поддерживает перевод на SQL".

..., что имеет смысл, но это что-то, что я могу сделать, чтобы сделать эту работу так, как я ее хочу? Или это ограничение, потому что я использую Linq для SQL и на самом деле что-то, что будет работать с Linq для объектов?

4b9b3361

Ответ 1

Оптимальная вещь о том, как LINQ to SQL обрабатывает выражения, состоит в том, что вы можете фактически создавать выражения в другом месте вашего кода и ссылаться на них в своих запросах. Почему бы вам не попробовать что-то вроде этого:

public static class Predicates
{
    public static Expression<Func<User, bool>> CheckForFlags()
    {
        return (user => user.Flag1 || user.Flag2 || user.Flag3 ||
                        user.Flag4 || user.Flag5);
    }

    public static Expression<Func<User, bool>> CheckForCriteria(string value)
    {
        return (user => user.Criteria1 == value);
    }
}

После определения ваших предикатов очень легко использовать их в запросе.

var users = DataContext.Users
    .Where(Predicates.CheckForFlags())
    .Where(Predicates.CheckForCriteria("something"));

Ответ 2

Вы пробовали PredicateBuilder? Я не использовал его более года, но я нашел его эффективным при написании запросов "Или где".

http://www.albahari.com/nutshell/predicatebuilder.aspx

Пример со своей страницы:

IQueryable<Product> SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Product>();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
  return dataContext.Products.Where (predicate);
}

Ответ 3

Я думаю, что это сработает, и я думаю, что я использовал его в своем проекте Linq-to-SQL, но я не могу найти пример без внимания. Если это не так, дайте мне знать.


Вместо создания функции создайте новое свойство объекта Users:

partial class Users {
   bool CheckForFlags
    {
       get { 
          return Flag1 || Flag2 || Flag3 || Flag4 || Flag5;
       }
    }
}

Затем вы должны иметь возможность делать

var users = DataContext.Users.Where(x => x.CheckForFlags);

Ответ 4

Насколько мне известно, существует два возможных способа сделать это.

Быстрый-простой способ фильтрации ваших результатов после выполнения SQL, с чем-то вроде этого:

var users = DataContext.Users.Where(x => x.Criteria1 == "something");
    .ToEnumerable()
    .Where(x => CheckForFlags(x));

Однако это очень плохое с точки зрения производительности. Он вернет ВСЕ строки из базы данных, соответствующие только первым критериям, а затем отфильтрует результаты в памяти на клиенте. Функциональный, но далеко не оптимальный.

Вторая, намного более эффективная опция - создать UDF в самой базе данных и вызвать ее из LINQ. См. Например этот вопрос. Очевидным недостатком является то, что он перемещает код в базу данных, которую никто не любит делать (по многим допустимым причинам).

Там могут быть и другие жизнеспособные решения, но это единственные, о которых я знаю.

Ответ 5

Как вы сказали, это ограничение, потому что вы используете Linq для SQL.

Что-то вроде этого должно работать:

var users = DataContext.Users.Where(x => x.Criteria1 == "something")
                             .ToArray()
                             .Where(x => CheckForFlags(x));