Динамическое предложение where в LINQ - с именами столбцов, доступными во время выполнения - PullRequest
9 голосов
/ 24 октября 2008

Отказ от ответственности: я решил проблему с помощью выражений из 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, как указано выше, не является вариантом.

Ответы [ 4 ]

13 голосов
/ 26 октября 2008

@ У Джеффа лучший выбор, только у 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.

7 голосов
/ 24 октября 2008
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"));

Обратите внимание, что они не являются взаимоисключающими.

2 голосов
/ 01 марта 2012

Вы можете включать и выключать предложения 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 имеет значение true в запросе, то условие на другой стороне оператора or будет игнорироваться.

0 голосов
/ 26 октября 2008

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

...