Мы работаем над программой просмотра журналов. У пользователя будет возможность фильтровать по пользователю, серьезности и т. Д. В дни Sql я бы добавил в строку запроса, но я хочу сделать это с помощью Linq. Как я могу условно добавить предложения where?
c#
linq
linq-to-sql
.net-3.5
sgwill
источник
источник
LINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Если вам нужно отфильтровать базу по списку / массиву, используйте следующее:
public List<Data> GetData(List<string> Numbers, List<string> Letters) { if (Numbers == null) Numbers = new List<string>(); if (Letters == null) Letters = new List<string>(); 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(); }
источник
Я закончил использовать ответ, похожий на ответ Дарена, но с интерфейсом IQueryable:
IQueryable<Log> 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<Type> HasID(this IQueryable<Type> query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; }
источник
Я решил это с помощью метода расширения, позволяющего условно включать LINQ в середине беглого выражения. Это устраняет необходимость разбивать выражение на
if
инструкции..If()
метод расширения:public static IQueryable<TSource> If<TSource>( this IQueryable<TSource> source, bool condition, Func<IQueryable<TSource>, IQueryable<TSource>> branch) { return condition ? branch(source) : source; }
Это позволяет сделать это:
return context.Logs .If(filterBySeverity, q => q.Where(p => p.Severity == severity)) .If(filterByUser, q => q.Where(p => p.User == user)) .ToList();
Вот также
IEnumerable<T>
версия, которая будет обрабатывать большинство других выражений LINQ:public static IEnumerable<TSource> If<TSource>( this IEnumerable<TSource> source, bool condition, Func<IEnumerable<TSource>, IEnumerable<TSource>> branch) { return condition ? branch(source) : source; }
источник
Другой вариант - использовать что-то вроде обсуждаемого здесь 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")
означает, что когда создается окончательный запрос, if
lastNameSearch
этоfalse
запрос полностью пропускает любой SQL для поиска по фамилии.источник
Это не самая красивая вещь, но вы можете использовать лямбда-выражение и при желании передать свои условия. В TSQL я делаю множество следующих действий, чтобы сделать параметры необязательными:
Вы можете продублировать тот же стиль с помощью следующей лямбды (пример проверки аутентификации):
источник
Недавно у меня было подобное требование, и в конце концов я нашел его в 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;
источник
Вы можете создать и использовать этот метод расширения
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate) { return isToExecute ? source.Where(predicate) : source; }
источник
Просто используйте оператор 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 будет оптимизирован.
источник
Что ж, я подумал, что вы можете поместить условия фильтрации в общий список предикатов:
var list = new List<string> { "me", "you", "meyou", "mow" }; var predicates = new List<Predicate<string>>(); predicates.Add(i => i.Contains("me")); predicates.Add(i => i.EndsWith("w")); var results = new List<string>(); foreach (var p in predicates) results.AddRange(from i in list where p.Invoke(i) select i);
В результате получается список, содержащий «я», «меня» и «косить».
Вы можете оптимизировать это, выполнив foreach с предикатами в совершенно другой функции, которая объединяет все предикаты по ИЛИ.
источник