【问题标题】:C# linq expression in lambda with containslambda中的C#linq表达式包含
【发布时间】:2014-02-20 21:11:49
【问题描述】:

我正在尝试利用“包含”来模拟旧 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吗?
  • 根据 Markus 的回答,可能使用 HashSet 而不是 List for Characteristica。
  • 不,我没有收到错误。我只是希望得到一份我需要的人的名单。我的示例是对象,但在实际代码中,我使用 EF 5 从数据库中检索数据。

标签: .net linq c#-4.0 lambda


【解决方案1】:

你的方法是正确的,但你应该使用Where而不是Select

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

并且你需要使用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 指出这一点是正确的任何一种方法都有效,但第二种方法更短,但可能不太明确。
【解决方案2】:

尝试以下方法:

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。

【讨论】:

  • Intersect 将与 LINQ to 对象一起使用,但如果您想针对数据库 (EF/L2S) 进行此操作,则需要使用 Contains。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 2018-09-29
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
相关资源
最近更新 更多