Условные запросы Linq
Мы работаем над Log Viewer. Использование будет иметь возможность фильтровать по пользователю, серьезность и т. Д. В Sql-дни я бы добавил к строке запроса, но я хочу сделать это с Linq. Как я могу условно добавить предложения where-clauses?
- Использование contains () в LINQ to SQL
- Как получить строку MAX с запросом GROUP BY в LINQ?
- LinqToSql объявляет и внедряет лучшую практику DataContext?
- Чтобы вернуть IQueryable или не вернуть IQueryable
- Понимание .AsEnumerable () в LINQ to SQL
- C # Linq to SQL: Как выразить «CONVERT ( AS INT)»?
- LINQ to SQL и общая сумма по упорядоченным результатам
- Как сделать левое внешнее соединение с помощью Dynamic Linq?
если вы хотите только фильтровать, если определенные критерии пройдены, сделайте что-то вроде этого
var logs = from log in context.Logs select log; if (filterBySeverity) logs = logs.Where(p => p.Severity == severity); if (filterByUser) logs = logs.Where(p => p.User == user);
Таким образом, ваше дерево выражений будет именно тем, что вы хотите. Таким образом, созданный SQL будет именно тем, что вам нужно, и не что иное.
Если вам необходимо отфильтровать базу в списке / массиве, используйте следующую команду:
public List GetData(List Numbers, List Letters) { if (Numbers == null) Numbers = new List (); if (Letters == null) Letters = new List (); var q = from d in database.table where (Numbers.Count == 0 || Numbers.Contains(d.Number)) where (Letters.Count == 0 || Letters.Contains(d.Letter)) select new Data { Number = d.Number, Letter = d.Letter, }; return q.ToList(); }
Я закончил использовать ответ, похожий на Daren’s, но с интерфейсом IQueryable:
IQueryable matches = m_Locator.Logs; // Users filter if (usersFilter) matches = matches.Where(l => l.UserName == comboBoxUsers.Text); // Severity filter if (severityFilter) matches = matches.Where(l => l.Severity == comboBoxSeverity.Text); Logs = (from log in matches orderby log.EventTime descending select log).ToList();
Это создает запрос перед удалением базы данных. Команда не будет работать до конца .ToList () в конце.
Когда дело доходит до условного linq, я очень люблю шаблон фильтров и труб.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
В основном вы создаете метод расширения для каждого случая фильтра, который принимает IQueryable и параметр.
public static IQueryable HasID(this IQueryable query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; }
Другой вариант – использовать что-то вроде PredicateBuilder, обсуждаемого здесь . Он позволяет писать код следующим образом:
var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone"); var classics = Product.ContainsInDescription ("Nokia", "Ericsson") .And (Product.IsSelling()); var query = from p in Data.Products.Where (newKids.Or (classics)) select p;
Обратите внимание: я только получил это, чтобы работать с Linq 2 SQL. EntityFramework не реализует Expression.Invoke, который необходим для работы этого метода. У меня есть вопрос по этой проблеме.
Делая это:
bool lastNameSearch = true/false; // depending if they want to search by last name,
имея это в заявлении where
:
where (lastNameSearch && name.LastNameSearch == "smith")
означает, что при создании окончательного запроса, если lastNameSearch
является false
запрос полностью опустит любой SQL для поиска по фамилии.
Это не самая красивая вещь, но вы можете использовать выражение lambda и передать свои условия в случае необходимости. В TSQL я делаю много следующих действий, чтобы сделать параметры необязательными:
WHERE Поле = @FieldVar ИЛИ @FieldVar IS NULL
Вы можете дублировать один и тот же стиль со следующей лямбдой (пример проверки подлинности):
MyDataContext db = new MyDataContext ();
void RunQuery (строка param1, строка param2, int? param3) {
Func checkUser = пользователь =>
((param1.Length> 0)? user.Param1 == param1: 1 == 1) &&
((param2.Length> 0)? user.Param2 == param2: 1 == 1) &&
((param3! = null)? user.Param3 == param3: 1 == 1);
Пользователь foundUser = db.Users.SingleOrDefault (checkUser);
}
Недавно у меня было подобное требование, и в конце концов я нашел это в MSDN. Примеры CSharp для Visual Studio 2008
Классы, включенные в образец загрузки DynamicQuery, позволяют создавать динамические запросы во время выполнения в следующем формате:
var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)");
Используя это, вы можете построить строку запроса динамически во время выполнения и передать ее в метод Where ():
string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; var q = from c in db.Customers.Where(queryString, null) orderby c.CompanyName select c;
Я решил это с помощью метода расширения, чтобы LINQ можно было условно включить в середине выражения жидкости. Это устраняет необходимость разложения выражения с помощью операторов if
.
.If()
метод расширения:
public static IQueryable If ( this IQueryable source, bool condition, Func, IQueryable > branch) { return condition ? source : branch(source); }
Это позволяет сделать это:
return context.Logs .If(filterBySeverity, q => q.Where(p => p.Severity == severity)) .If(filterByUser, q => q.Where(p => p.User == user)) .ToList();
Просто используйте оператор C # &&:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Редактировать: Ах, нужно читать более внимательно. Вы хотели знать, как условно добавлять дополнительные предложения. В этом случае я понятия не имею. 🙂 То, что я бы сделал, это просто подготовить несколько запросов и выполнить правильный, в зависимости от того, что мне нужно.
Вы можете использовать внешний метод:
var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... }
Это будет работать, но не может быть разбито на деревья выражений, что означает, что Linq to SQL будет запускать контрольный код для каждой записи.
В качестве альтернативы:
var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec;
Это может работать в деревьях выражений, что означает, что Linq to SQL будет оптимизирован.
Ну, как я думал, вы могли бы включить условия фильтра в общий список Predicates:
var list = new List { "me", "you", "meyou", "mow" }; var predicates = new List>(); predicates.Add(i => i.Contains("me")); predicates.Add(i => i.EndsWith("w")); var results = new List (); foreach (var p in predicates) results.AddRange(from i in list where p.Invoke(i) select i);
Это приводит к списку, содержащему «меня», «meyou» и «косить».
Вы можете оптимизировать это, выполнив foreach с предикатами в совершенно другой функции, которая ORs все предикаты.