Динамическое предложение WHERE в LINQ - PullRequest
51 голосов
/ 11 мая 2009

Каков наилучший способ собрать динамическое предложение WHERE в оператор LINQ?

У меня есть несколько десятков флажков в форме, и я передаю их обратно в виде: Dictionary > (Dictionary >) на мой запрос LINQ.

public IOrderedQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string,List<string>> filterDictionary)
{
    var q = from c in db.ProductDetail
            where c.ProductGroupName == productGroupName && c.ProductTypeName == productTypeName
            // insert dynamic filter here
            orderby c.ProductTypeName
            select c;
    return q;
}

Ответы [ 10 ]

52 голосов
/ 11 мая 2009

alt text
(источник: scottgu.com )

Тебе нужно что-то подобное? Используйте динамическую библиотеку запросов Linq (загрузка включает примеры).

Проверьте блог ScottGu для большего количества примеров.

13 голосов
/ 13 мая 2009

Вы также можете использовать PredicateBuilder из LinqKit для объединения нескольких типов лямбда-выражений с безопасностью, используя Or или And.

http://www.albahari.com/nutshell/predicatebuilder.aspx

10 голосов
/ 30 июля 2014

У меня есть похожий сценарий, в котором мне нужно добавить фильтры на основе пользовательского ввода, и я добавляю в цепочку предложение where.

Вот пример кода.

var votes = db.Votes.Where(r => r.SurveyID == surveyId);
if (fromDate != null)
{
    votes = votes.Where(r => r.VoteDate.Value >= fromDate);
}
if (toDate != null)
{
    votes = votes.Where(r => r.VoteDate.Value <= toDate);
}
votes = votes.Take(LimitRows).OrderByDescending(r => r.VoteDate);
8 голосов
/ 20 марта 2013

Простой подход может быть, если ваши столбцы имеют простой тип, например String

public static IEnumerable<MyObject> WhereQuery(IEnumerable<MyObject> source, string columnName, string propertyValue)
{
   return source.Where(m => { return m.GetType().GetProperty(columnName).GetValue(m, null).ToString().StartsWith(propertyValue); });
}
5 голосов
/ 01 марта 2014

Я придумал решение, которое даже я могу понять ... используя метод «Содержит», вы можете связать столько ГДЕ, сколько захотите. Если WHERE - пустая строка, она игнорируется (или оценивается как выделение всех). Вот мой пример объединения двух таблиц в LINQ, применения нескольких выражений where и заполнения класса модели для возврата в представление. (это выбрать все).

public ActionResult Index()
    {
        string AssetGroupCode = "";
        string StatusCode = "";
        string SearchString = "";

        var mdl = from a in _db.Assets
                  join t in _db.Tags on a.ASSETID equals t.ASSETID
                  where a.ASSETGROUPCODE.Contains(AssetGroupCode)
                  && a.STATUSCODE.Contains(StatusCode)
                  && (
                  a.PO.Contains(SearchString)
                  || a.MODEL.Contains(SearchString)
                  || a.USERNAME.Contains(SearchString)
                  || a.LOCATION.Contains(SearchString)
                  || t.TAGNUMBER.Contains(SearchString)
                  || t.SERIALNUMBER.Contains(SearchString)
                  )
                  select new AssetListView
                  {
                      AssetId = a.ASSETID,
                      TagId = t.TAGID,
                      PO = a.PO,
                      Model = a.MODEL,
                      UserName = a.USERNAME,
                      Location = a.LOCATION,
                      Tag = t.TAGNUMBER,
                      SerialNum = t.SERIALNUMBER
                  };


        return View(mdl);
    }
2 голосов
/ 11 мая 2009

У меня был такой же вопрос ( Пользовательский фильтр для linq ), и @tvanfosson рассказал мне о Dynamic Linq (http://code.msdn.microsoft.com/csharpsamples).

1 голос
/ 22 февраля 2019

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

Список productList = новый список ();

        productList =
                db.ProductDetail.Where(p => p.ProductDetailID > 0 //Example prop
                && (String.IsNullOrEmpty(iproductGroupName) ? (true):(p.iproductGroupName.Equals(iproductGroupName)) ) //use ternary operator to make the condition dynamic
                && (ID == 0 ? (true) : (p.ID == IDParam))
                ).ToList();
1 голос
/ 17 декабря 2017

Это решение, которое я придумала, если кому-то интересно.

https://kellyschronicles.wordpress.com/2017/12/16/dynamic-predicate-for-a-linq-query/

Сначала мы определяем тип отдельного элемента, который нам нужно использовать (Of TRow As DataRow), а затем идентифицируем «источник», который мы используем, и привязываем идентификатор к этому источнику ((source As TypedTableBase (Of TRow)). Затем мы должен указать предикат или предложение WHERE, которое должно быть передано (предикат As Func (Of TRow, Boolean)), которое будет возвращено как true или false. Затем мы определяем, как мы хотим, чтобы возвращаемая информация была упорядочена (OrderByField As String Затем наша функция возвратит EnumerableRowCollection (Of TRow), нашу коллекцию datarows, которые выполнили условия нашего предиката (EnumerableRowCollection (Of TRow)). Это базовый пример. Конечно, вы должны убедиться, что поле вашего заказа не имеет не содержат пустых значений или правильно обработали эту ситуацию и убедитесь, что имена столбцов (если вы используете строго типизированный источник данных, не обращайте на это внимания, они переименуют столбцы для вас) являются стандартными.

1 голос
/ 22 сентября 2013

Этот проект на CodePlex имеет то, что вы хотите.

System.Linq.Dynamic - http://dynamiclinq.codeplex.com/

Описание проекта

Расширяет System.Linq.Dynamic для поддержки выполнения лямбда-выражений, определенных в строке, в Entity Framework или любом поставщике, поддерживающем IQueryable.

Поскольку это расширение исходного кода, которое вы можете найти в Блоге Скотта Гатри , оно позволит вам делать такие вещи:

enter image description here

И такие вещи:

enter image description here

1 голос
/ 27 августа 2013

Вы можете использовать метод расширения Any (). Мне кажется, что следующее работает.

XStreamingElement root = new XStreamingElement("Results",
                from el in StreamProductItem(file)
                where fieldsToSearch.Any(s => el.Element(s) != null && el.Element(s).Value.Contains(searchTerm))
                select fieldsToReturn.Select(r => (r == "product") ? el : el.Element(r))
            );
            Console.WriteLine(root.ToString());

Где 'fieldsToSearch' и 'fieldsToReturn' оба являются объектами List.

...