Динамическое предложение where в LINQ — с именами столбцов, доступными во время выполнения

Отказ от ответственности: я решил проблему, используя выражения из System.Linq.Expressions, но я все еще ищу лучший/более простой способ.

Рассмотрим следующую ситуацию:

var query = 
    from c in db.Customers
    where (c.ContactFirstName.Contains("BlackListed") || 
           c.ContactLastName.Contains("BlackListed")  ||
           c.Address.Contains("BlackListed"))
    select c;

Столбцы/атрибуты, которые необходимо проверить на соответствие термину из черного списка, доступны мне только во время выполнения. Как создать это динамическое предложение where?

Дополнительная сложность заключается в том, что коллекция Queryable (db.Customers выше) типизирована для Queryable базового класса «Customer» (скажем, «Person»), и поэтому писать c.Address, как указано выше, нельзя.


person sandesh247    schedule 24.10.2008    source источник
comment
Мне было бы интересно увидеть ваше решение Expressions, есть ли шанс добавить к вашему ответу? Ваше здоровье.   -  person Kev    schedule 24.10.2008
comment
См. этот вопрос и мой последующий ответ относительно динамических запросов LINQ   -  person Geoff    schedule 24.10.2008


Ответы (4)


У @Geoff есть лучший вариант, просто Dynamic LINQ.

Если вы хотите пойти по пути создания запросов во время выполнения с помощью Lambda, я бы порекомендовал вам использовать PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) и иметь что-то вроде этого:

Expression<Fun<T,bool>> pred = null; //delcare the predicate to start with. Note - I don't know your type so I just used T 
if(blacklistFirstName){
  pred = p => p.ContactFirstName.Contains("Blacklisted");
}
if(blacklistLastName){
  if(pred == null){
    pred = p => p.ContactLastName.Contains("Blacklisted"); //if it doesn't exist just assign it
  }else{
    pred = pred.And(p => p.ContactLastName.Contains("Blacklisted"); //otherwise we add it as an And clause
  }
}

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

var results = db.Customers.Where(pred).Select(c => c);

Я использовал это для создания LINQ для поиска, где есть около 20 различных вариантов, и это дает действительно хороший SQL.

person Aaron Powell    schedule 25.10.2008
comment
Разве предикат не должен быть скомпилирован? - person clklachu; 19.12.2012

var query = from C in db.Customers select c;

if (seachFirstName)
         query = query.Where(c=>c.ContactFirstname.Contains("Blacklisted"));

if (seachLastName)
         query = query.Where(c=>c.ContactLastname.Contains("Blacklisted"));

if (seachAddress)
         query = query.Where(c=>c.Address.Contains("Blacklisted"));

Обратите внимание, что они не исключают друг друга.

person James Curran    schedule 24.10.2008

Вы можете включать и выключать предложения where, используя некоторые логические выражения.

//Turn on all where clauses
bool ignoreFirstName = false;
bool ignoreLastName = false;;
bool ignoreAddress = false;

//Decide which WHERE clauses we are going to turn off because of something.
if(something)
    ignoreFirstName = true; 

//Create the query
var queryCustomers = from c in db.Customers 
    where (ignoreFirstName || (c.ContactFirstName.Contains("BlackListed")))
    where (ignoreLastName || (c.ContactLastName.Contains("BlackListed")))
    where (ignoreAddress || (c.Address.Contains("BlackListed"))
    select j;  

Если в запросе ignoreFirstName истинно, то условие на другой стороне оператора or будет проигнорировано.

person timothy    schedule 01.03.2012

Поскольку это не LINQ to Objects, а скорее LINQ to SQL, у вас нет другой альтернативы, кроме использования выражений или хранимой процедуры.

person Omer van Kloeten    schedule 25.10.2008