在linq中使用ALL运算符来过滤EntitySet的子项

时间:2010-08-19 17:28:22

标签: linq

我有两个对象如下:

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();
}

但是,这似乎不起作用。关于我做错了什么想法吗?

EDIT1:标签被修剪并且是“小写的”。

2 个答案:

答案 0 :(得分:1)

这是因为您将项目中的标记设置为小写,而不是搜索的标记。

通过这种修改,它应该有效:

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();

更新:这是一个带有lambda语法的版本。由于临时匿名类型,它非常难看,但这就是let子句转换为lambda ...

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();

答案 1 :(得分:0)

我认为你需要做这样的事情:

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作为列表,然后然后按创建日期排序。这意味着数据库中没有进行排序。一旦你将某些东西变成了List,你就会放弃延迟执行的好处,因为你会将整个集合带回内存。

编辑:这是证明它在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();
    }

如果你想匹配Item的ItemTag列表中的任何标签,那么只需将All改为Any。

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