2009-03-07 3 views
2

Как я пишу динамический запрос для Linq, если у меня есть сказать, класс Customer, который имеет поля:Динамический запрос в LINQ

string name 
string address 
int phoneno 

я должен запроса на основе информации, предоставляемой аналогична

query = string.Empty; 

if(!string.IsNullorEmpty(name)) 
{ 
    query += "@name = name"; 
} 

if(!string.IsNullorEmpty(address)) 
{ 
    query += "@address = address"; 
} 

if(!string.IsNullorEmpty(phoneno)) 
{ 
    query += "@phoneno = phoneno"; 
} 

var result = from condition in customer 
    where(query) 
    select condition; 

Edit # 1:

детали изменчива во время выполнения, как

private Customer[] GetCustomers(Dictionary<string,string> attributes) 
{ 
    here the attribute may be, name alone, or name and address, or name address and phoneno 


     foreach(string field in attributes.key) 
     { 
      query += field == attributes[key]; 

     } 

     Customers[] =ExecuteQuery(query); 

} 

Этот запрос поддерживается LINQ?

Edit # 2:

Привет Mouk,
Как я новичок в C#, я до сих пор изо всех сил, это не работает для меня.

var query = _ConfigFile.ConnectionMasterSection; 

for(int i = 0; i < filter.count; i++) 
{ 
    query = result.Where(p => typeof(ConnectionMaster).GetProperty(filter[i].Attribute).Name == filter[i].Value); 
} 

Это yeilds Empty, где, как я использовал этот

var query = _ConfigFile.ConnectionMasterSection; 

//Hard coded 
res.Where(q => q.category == filter[0].Value); 

И это сработало, как я ожидал.

Hi Bryan Watts,
Я также попробовал ваш код, и я получаю эту ошибку: «Lambda Parameter is not in scope».

for(int i = 0; i < filter.count; i++) 
{ 
    Field item = filter[i]; 

    MemberExpression param = Expression.MakeMemberAccess(Expression.Parameter(typeof(Connection), "p"), typeof(Connection).GetProperty(item.Attribute)); 

    MemberExpression constant = Expression.MakeMemberAccess(Expression.Constant(item), typeof(Field).GetProperty("Value")); 
} 


try 
{ 
    var myquery = Queryable.Where(coll, Expression.Lambda<Func<Connection, bool>>(
    Expression.Equal(param, constant), Expression.Parameter(typeof(Connection),"p"))); 
} 

Какая ошибка?

+0

Добавлен пример моего ответа, который должен вести вас до конца. –

ответ

5

Проверьте это http://www.albahari.com/nutshell/predicatebuilder.aspx, он позволяет строго типизированное здание предиката, это может быть очень приятно. Если вам нужны динамические строковые предикаты, то вы можете использовать LINQ Dynamic Query Library от ScottGu.

Оба будут выполнять то, что вы хотите, хотя я бы порекомендовал первый вариант перед вторым.

Позволяя сделать:

var predicate = PredicateBuilder.True<MyLinqType>(); 

if(!string.IsNullOrEmpty(name)) 
    predicate = predicate.And(p => p.name == name); 


... 

var myResults = Context.MyLinTypeQueryTable.Where(predicate); 

И еще.

3

Здесь вы идете:

var result = from customer in Customers 
      where string.IsNullOrEmpty(phoneNo) || customer.PhoneNo == phoneNo 
      where string.IsNullOrEmpty(address) || customer.Address == address 
      select customer; 

Если вы обеспокоены тем, что это сгенерировать оптимальный запрос SQL внизу, как всегда, вы должны приложить SQL Query Analyzer и проверить. Но я считаю, что синтаксический анализатор выражений в Linq To Sql сглаживает предложения where в зависимости от значения аргументов.

0

Вы можете использовать свободный интерфейс и добавить новое предложение Where fpr для каждого условия. Что-то вроде:

var result = from cus in customers select cus; 
if(!string.IsNullOrEmpty(name)) 
     result= result.Where(p => p.Name == name); 

EDIT при Hte комментарий:

, если вы запрашиваете по коллекции в памяти, можно получить свойства с помощью отражения.

private Customer[] GetCustomers(Dictionary<string,string> attributes) 
{ 
     var result = from cus in customers select cus;  

     foreach(string key in attributes.Keys) 
      result= result.Where(p => GetProperty(p, key)== attributes[key]); 

     return result.ToList();  
} 

Предполагая, что GetProperty возвращает свойство путем отражения.

Используя Linq2Sql, этот метод приведет к извлечению всех записей, а затем их повторению с использованием отражения.

0

См. Редактировать # 1 в оригинальном вопросе.

+0

Да, это связано с LINQ Dynamic Query Library, с которой я связан. Вам просто нужно будет построить строку. Просто обратите внимание, вы не должны добавлять ответ, который не является ответом, поскольку это не форум, вместо этого измените исходный вопрос, чтобы включить изменения. –

0

Похоже, вам нужно динамически составлять запросы.

См. my answer по this question.

В нем объясняется, как запросы от IQueryable<T> составлены компилятором и что вы можете сделать, чтобы добавить динамические элементы.

Редактировать

Вот пример того, как вы динамически создавать набор Where условий на вершине IQueryable<Customer>:

// This method ANDs equality expressions for each property, like so: 
// 
// customers.Where(c => c.Property1 == value1 && c.Property2 == value2 && ...); 

private IQueryable<Customer> FilterQuery(IQueryable<Customer> customers, IDictionary<string, string> filter) 
{ 
    var parameter = Expression.Parameter(typeof(Customer), "c"); 
    Expression filterExpression = null; 

    foreach(var filterItem in filter) 
    { 
     var property = typeof(Customer).GetProperty(filterItem.Key); 
     var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
     var equality = Expression.Equal(propertyAccess, Expression.Constant(filterItem.Value)); 

     if(filterExpression == null) 
     { 
      filterExpression = equality; 
     } 
     else 
     { 
      filterExpression = Expression.And(filterExpression, equality); 
     } 
    } 

    if(filterExpression != null) 
    { 
     var whereBody = Expression.Lambda<Func<Customer, bool>>(filterExpression, parameter); 

     customers = customers.Where(whereBody); 
    } 

    return customers; 
} 
0

Я имел хороший опыт работы с Dynamic LINQ.

Я использовал его для богатой таблицы HTML, которую можно было отфильтровать и отсортировать на стороне сервера. Сервер получает запрос, содержащий параметр запроса, где ключ - это имя свойства (например, «Фамилия»), а значение - это значение, которое необходимо сортировать для свойства (например, «Смит»). Используя эту информацию, я построил строку запроса, которую я передал в метод Dynamic LINQ Where.

Грубо говоря, вы могли бы придумать что-то вроде следующего:

public static IQueryable<T> Filter<T>(this IQueryable<T> query, Dictionary<string, string> dictionary) 
{ 
    Type t = typeof(T); 
    StringBuilder sb = new StringBuilder(); 
     PropertyInfo[] properties = t.GetProperties(); 
     foreach(string key in dictionary.Keys) 
     { 
      PropertyInfo property = properties.Where(p => p.Name == key).SingleOrDefault(); 
      if(property != null) 
      { 
       if (sb.Length > 0) sb.Append(" && "); 

       string value = dictionary[key]; 

       sb.Append(string.Format(@"{0}.ToString().Contains(""{1}"")", key, value)); 
      } 
     } 

     if (sb.Length > 0) 
     return query.Where(sb.ToString()); 
    else 
      return query; 
} 

Код из верхней части моей головы, и, таким образом, непроверенной.

Конечно, это самая простая версия: это простое сравнение строк. Если вы хотите иметь числовое сравнение (то есть вы хотите, например, User, где UserID - ровно 100, а не где UserID.ToString().Contains("100")), или запрос вложенных свойств (например, Customer.Company.CompanyAddress) или запрос Collections, это становится более сложным. Вы также должны думать о безопасности: в то время как Dynamic LINQ не уязвим для SQL-инъекции, вы не должны позволять ей слепо разбирать все пользовательские ввод.

Смежные вопросы