Динамическое предложение where с использованием Linq to SQL в запросе соединения в приложении MVC - PullRequest
2 голосов
/ 28 мая 2010

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

Продукты -Я бы -CategoryId

Категории [Id, Name, UrlName]

Свойства [Id, CategoryId, Name, UrlName]

PropertyValues ​​ [Id, PropertyId, Text, UrlText]

ProductPropertyValues ​​ [ProductId, PropertyValueId]

Когда я добавляю товар в каталог, будет добавлено несколько значений ProductPropertyValues ​​в зависимости от категории, и я хотел бы иметь возможность фильтровать все товары из категории, выбирая значения для одного или нескольких свойств. Бизнес-логика, а также индексы и ограничения SQL гарантируют, что все UrlNames и тексты являются уникальными для свойств и категорий значений.

Решением будет приложение, основанное на коде MVC3 EF, и маршрутизация настраивается следующим образом:

/products/{categoryUrlName}/{*filters}

Часть маршрутизации фильтра имеет переменную длину, поэтому можно применять несколько фильтров. Каждый фильтр содержит UrlName свойства и UrlText значения, разделенные подчеркиванием.

URL-адрес может выглядеть следующим образом / products / sites / framework_mvc3 / language_csharp

Я соберу все фильтры, которые буду хранить в списке, прочитав URL. Теперь пришло время на самом деле получить продукты, основанные на нескольких свойствах, и я пытался найти правильную стратегию.

Может быть, есть другой способ реализации фильтров. Все крупные интернет-магазины используют фильтры, зависящие от категории, и я все еще ищу лучший способ реализовать постоянную часть для этого типа функциональности. Предлагаемые решения приводят к «или» результирующему набору, если выбрано несколько фильтров. Я могу себе представить, что добавление свойства text в таблицу product, в которой все значения свойств хранятся в виде объединенной строки, также может работать. Я понятия не имею, во что это обойдется с точки зрения производительности. При аренде не будет сложного соединения, а свойства и их значения будут в любом случае получены в виде текста.

Может быть, механизм фильтрации можно сделать хорошо на стороне клиента.

Ответы [ 4 ]

0 голосов
/ 28 февраля 2018

Я знаю, что это старый ответ, но если кто-то увидит это, я построил этот проект:

https://github.com/PoweredSoft/DynamicLinq

Который также должен быть загружен на nuget:

https://www.nuget.org/packages/PoweredSoft.DynamicLinq

Вы можете использовать это, чтобы пройтись по фильтру, поступающему из строки запроса, и сделать что-то в строках

query = query.Query(q =>
{
    q.Compare("AuthorId", ConditionOperators.Equal, 1);
    q.And(sq =>
    {
        sq.Compare("Content", ConditionOperators.Equal, "World");
        sq.Or("Title", ConditionOperators.Contains, 3);
    });
});
0 голосов
/ 31 мая 2010
IEnumerable<int> filters = filterList.Select(pf => pf.ValueId);

var products = from pp in ProductPropertyRepository
               where filters.Contains(pp.PropertyValueId) 
               && pp.Product.Category.Name == category
               select pp.Product;

Имейте в виду, что при использовании Contains фильтры будут передаваться как параметры sproc, это означает, что вам следует соблюдать осторожность, чтобы не превысить предел параметра sproc.

0 голосов
/ 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);
}
0 голосов
/ 28 мая 2010

Сложная часть этого - отправка всего списка в базу данных в качестве фильтра. Ваш подход состоит в том, чтобы создавать все больше и больше, где могут работать предложения:

productsInCategory = ProductRepository
  .Where(p => p.Category.Name == category); 

foreach (PropertyFilter pf in filterList) 
{
     PropertyFilter localVariableCopy = pf;
     productsInCategory = from product in productsInCategory
       where product.ProductProperties
         .Any(pp => pp.PropertyValueId == localVariableCopy.ValueId)
       select product; 
}

Другой способ - отправить весь список с использованием метода List.Contains

List<int> valueIds = filterList.Select(pf => pf.ValueId).ToList();

productsInCategory = ProductRepository
  .Where(p => p.Category.Name == category)
  .Where(p => p.ProductProperties
    .Any(pp => valueIds.Contains(pp.PropertyValueId)
  );
...