C#中使用lambda表达式的linq语句中包含contains方法。

15

我试图使用“contains”方法来模拟旧的SQL“where id in (1,2,3,4)”过滤查询的方式。

然而,当我的ID在更深层级时,使用它存在一些困难。

代码:

 public class Category
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }

    public class Characteristica
    {
        public Category Category { get; set; }
        public int Id { get; set; }
        public string Value { get; set; }
    }

    public class Person
    {
        public string Name { get; set; }
        public List<Characteristica> Appearance { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var persons = new List<Person>
            {
                new Person { Name = "Person A", Appearance = new List<Characteristica> { new Characteristica { Id = 22 }, new Characteristica { Id = 5 }, new Characteristica { Id = 12 } }},
                new Person { Name = "Person B", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 6 }, new Characteristica { Id = 11 } }},
                new Person { Name = "Person C", Appearance = new List<Characteristica> { new Characteristica { Id = 2 }, new Characteristica { Id = 8 }, new Characteristica { Id = 13 } }},
                new Person { Name = "Person D", Appearance = new List<Characteristica> { new Characteristica { Id = 2 }, new Characteristica { Id = 5 }, new Characteristica { Id = 10 } }},
                new Person { Name = "Person E", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 8 }, new Characteristica { Id = 10 } }},
                new Person { Name = "Person F", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 6 }, new Characteristica { Id = 23 } }},
            };

            var listOfSearchedIds = new List<int> { 22, 23 };
            var selected = persons.Select(p => p.Appearance.Where(a => listOfSearchedIds.Contains(a.Id))).ToList();
        }
    }

现在我正在尝试使用contains特性从我的集合中取出“Person A”和“Person F”,但是我无法看出我在这里做错了什么。

有人可以指点一下我做错了什么吗?我已经尝试过不同版本的lambda表达式,但这是我能接近的最佳结果,但我从表达式中得到了所有6个项目。


发生了什么?你有错误吗?你得到了错误的信息吗?我原以为你是在与数据库进行交互,但你的示例看起来不像是这样。你能把它放在complify.net上吗? - George Mauer
与Markus的答案一致,也许可以使用HashSet而不是List来处理Characteristica。 - paparazzo
不,我没有遇到错误。我只是期望得到我所需的人员列表。我的示例是使用对象,但在真实的代码中,我是使用 EF 5 从数据库检索数据。 - codingjoe
2个回答

34
您的方法是正确的,但您应该使用 Where 而不是 Select
 var selected = persons.Where(p => p.Appearance
                .Where(a => listOfSearchedIds.Contains(a.Id))
                .Any()).ToList();

你需要使用Any来检查p.Appearance.Where返回的序列是否包含任何元素。或者您可以直接使用Any使其更简短:

而您需要使用Any来检查p.Appearance.Where返回的序列是否包含任何元素。或者您可以直接使用Any使其更简短:

var selected = persons.Where(p => p.Appearance
                .Any(a => listOfSearchedIds.Contains(a.Id))
                .ToList();

我在LINQPad 5中测试了这两种方法,它们最终产生了相同的SQL。DECLARE p0 Int = 2 DECLARE p1 Int = 3 SELECT [t0].[Id], [t0].[Name], [t0].[Description], [t0].[ModifiedBy], [t0].[ModifiedDate], [t0].[CreatedBy], [t0].[CreatedDate], [t0].[RowVersion], [t0].[TriggerTypeGuid] FROM [TriggerType] AS [t0] WHERE EXISTS(SELECT NULL AS [EMPTY] FROM [TriggerClass] AS [t1] WHERE ([t1].[TriggerTypeId] IN (p0, p1)) AND ([t1].[TriggerTypeId] = [t0].[Id]))因此,Selman指出两种方法都可以,但第二种方法可能更短,但也许不够明确。 - Latin Warrior

3
尝试以下方法:
var listOfSearchedIds = new List<int> { 22, 23 };
var selected = persons
        .Where(p => listOfSearchedIds
                        .Intersect(p.Appearance
                             .Select(a => a.Id)).Any()).ToList();

使用Intersect,您可以比较两个列表并返回它们共同包含的项。Intersect在内部使用HashSet,因此是查找两个集合交集的一种高效方法。Any()如果结果列表中至少有一项,则返回true。


1
Intersect可以与LINQ to objects一起使用,但如果您想针对数据库(EF/L2S)执行此操作,则需要使用Contains。 - Jim Wooley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接