Использование оператора ALL в linq для фильтрации дочерних элементов EntitySet - PullRequest
1 голос
/ 19 августа 2010

У меня есть два объекта следующим образом:

public class Item
{
    public int ItemId {get;set;}
    public string ItemName {get;set;}
    public List<Tag> ItemTags {get;set;}
    public DateTime DateCreated {get;set;}
}

public class Tag
{
    public int TagId {get;set;}
    public string TagName {get;set;}
}

Это объекты LINQ-to-SQL, поэтому ItemTags будет EntitySet.

Я пытаюсь выполнить поискзапрос, в котором пользователь может предоставить список тегов, разделенных запятыми, в качестве фильтра поиска.

Как отфильтровать мой список элементов, который содержит все теги в списке, разделенном запятыми.

EDIT2

e.g.
Item1 has tags of Apple, Banana, Orange
Item2 has tags of Banana, Orange
Item3 has tags of Pineapple, Orange
If the tag filter is "Banana, Orange" I need the results to be Item1 and Item2.

/ EDIT2

Это то, что я пробовал до сих пор:

string tags = "Manchester United,European Cup,2008";
List<string> tagsList = tags.Trim().ToLower()
    .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
    .Distinct(StringComparer.CurrentCultureIgnoreCase)
    .ToList();

List<Item> itemList = ItemRepository.FetchAll();

var query = itemList
    .OrderByDescending(p => p.DateCreated)
    .ToList();

if (tagsList.Count() > 0)
{
    query = query
        .Where(p => p.ItemTags
            .Select(q => q.TagName.ToLower())
            .All(r => tagsList.Contains(r)))
        .ToList();
}

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

РЕДАКТИРОВАТЬ1: теги обрезаны и «в нижнем регистре».

Ответы [ 2 ]

1 голос
/ 19 августа 2010

Это потому, что вы помещаете теги элементов в нижний регистр, а не искомые теги.

В этой модификации она должна работать:

List<string> tagsList = tags
    .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
    .Select(s => s.ToLower())
    .Distinct()
    .ToList();

РЕДАКТИРОВАТЬ:Хорошо, я вижу, в чем проблема: вы делаете это задом наперед.Вы ищете элементы, которые имеют только теги, которые вы ищете.

Попробуйте вместо этого:

query = 
    (from item in query
     let itemTags = p.ItemTags.Select(it => it.TagName.ToLower())
     where tags.All(t => itemTags.Contains(t))
     select item).ToList();

ОБНОВЛЕНИЕ: вотверсия с лямбда-синтаксисом.Это довольно уродливо из-за временного анонимного типа, но вот как выражение let переводится в лямбду ...

query =
    query.Select(item => new { item, itemTags = item.ItemTags.Select(it => it.TagName.ToLower()) })
         .Where(x => tagsList.All(t => x.itemTags.Contains(t)))
         .Select(x => x.item)
         .ToList();
0 голосов
/ 19 августа 2010

Я думаю, вам нужно сделать что-то вроде этого:

var query = itemList.OrderByDescending(p => p.DateCreated).ToList();

var results = query.Where(i => i.ItemTags
   .All(it => tagsList.Contains(it.TagName.ToLower())));

Тогда results должен составить список подходящих элементов.

PS.Ваш код показывает, что вы выбираете itemList в виде списка из вашего хранилища и , а затем сортируете по дате создания.Это означает, что сортировка не выполняется в базе данных.Как только вы превращаете что-то в список, вы отказываетесь от преимуществ отложенного выполнения, поскольку вы возвращаете всю коллекцию в память.

РЕДАКТИРОВАТЬ: вот тестовый код, чтобы доказать, что он работает в Linq to Objects:

public class Item
{
    public int ItemId { get; set; }
    public string ItemName { get; set; }
    public List<Tag> ItemTags { get; set; }
    public DateTime DateCreated { get; set; }
}

public class Tag
{
    public int TagId { get; set; }
    public string TagName { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        RunTags();
    }

    private static void RunTags()
    {
        Item i1 = new Item()
        {
            ItemId = 1,
            ItemName = "Item1",
            ItemTags = new List<Tag>() { new Tag { TagId = 1, TagName = "2008" }, new Tag { TagId = 2, TagName = "Donkey" } }
        };

        Item i2 = new Item()
        {
            ItemId = 2,
            ItemName = "Item2",
            ItemTags = new List<Tag>() { new Tag { TagId = 4, TagName = "Cat" }, new Tag { TagId = 2, TagName = "Donkey" }, new Tag { TagId = 3, TagName = "Seattle" } }
        };

        Item i3 = new Item()
        {
            ItemId = 3,
            ItemName = "Item3",
            ItemTags = new List<Tag>() { new Tag { TagId = 523, TagName = "Manchester united" }, new Tag { TagId = 10, TagName = "European Cup" }, new Tag { TagId = 1, TagName = "2008" } }
        };

        Item i4 = new Item()
        {
            ItemId = 4,
            ItemName = "Item4",
            ItemTags = new List<Tag>() { new Tag { TagId = 05, TagName = "Banana" }, new Tag { TagId = 140, TagName = "Foo" }, new Tag { TagId = 4, TagName = "Cat" } }
        };

        Item i5 = new Item()
        {
            ItemId = 5,
            ItemName = "Item5",
            ItemTags = new List<Tag>() { new Tag { TagId = 05, TagName = "Banana" }, new Tag { TagId = 140, TagName = "Foo" } }
        };

        List<Item> itemList = new List<Item>() { i1, i2, i3, i4, i5 };

        string tags = "Manchester United,European Cup,2008";
        List<string> tagsList = tags.Trim().ToLower()
            .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
            .Distinct(StringComparer.CurrentCultureIgnoreCase)
            .ToList();

        var query = itemList
            .OrderByDescending(p => p.DateCreated).ToList();


        var results = query.Where(i => i.ItemTags.All(it => tagsList.Contains(it.TagName.ToLower())));

        foreach (var item in results)
        {
            Console.WriteLine(item.ItemName); // Should return "Item3"
        }

        Console.ReadLine();
    }

Если вы хотите сопоставить какой-либо из тегов в списке ItemTag элемента, просто измените Все на Любой, т.е.

var results = query.Where(i => i.ItemTags.Any(it => tagsList.Contains(it.TagName.ToLower())));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...