Linq 从一个列表中获取对象,其中其他整数列表包含在第一个列表中

Posted

技术标签:

【中文标题】Linq 从一个列表中获取对象,其中其他整数列表包含在第一个列表中【英文标题】:Linq get object from one list where other list of integers are contained in the first list 【发布时间】:2020-10-04 10:53:03 【问题描述】:

我有以下类结构:

public class Party 
 public int Id get;set;
 public List<int> PartyAgents get;set;

还有一个 PartyAgents 的整数列表 => public List&lt;int&gt; PartyAgentIds get;set;

我如何获得所有 Party 包含列表中的派对代理的各方

我试过了:

var domainParties = (from party in _context.Party   //.Include("Address")
                                   where party.PartyAgents.Any(agent =>
                                         PartyAgentIds.Contains(agent))
                                   select party).ToList();

但这是抛出错误

无法翻译查询。要么重写表单中的查询 可以翻译,或通过以下方式显式切换到客户评估 插入对 AsEnumerable()、AsAsyncEnumerable() 的调用, ToList() 或 ToListAsync()。

【问题讨论】:

尝试将_context.Party 更改为_context.Party.ToList() 你确定你的数据库结构看起来像那样...我的“猜测”它是 PartyAgents 是子表的集合导航属性,这使得问题完全不同,解决方案又不同了 【参考方案1】:

Take #1 - 使用简短的 sn-p 代码快速尝试执行此操作;有一个合理的机会使用 EF,因为只有 _context.Party.Where(p => p.PartyAgents.Contains(i) 需要翻译成 SQL,但这意味着运行多个查询:(

List<Party> domainParties = new List<Party>();
List<int> partyAgentIds = new List<int> 1, 3, 5, 7, 9 ; 

partyAgentIds.ForEach( 
    (i) => domainParties.AddRange ( 
        _context.Party.Where(p => p.PartyAgents.Contains(i) 
        && !domainParties.Contains(p)
        )
    )
);

采取 #2 - 动态表达式应该更有效,因为它对数据库进行一次查询。已经测试了这个特定的代码,它适用于 Party 类的 IQueryable 集合,我之前也在 EF Core 中使用过这种类型的代码。

if (partyAgentIds.Count() > 0)

    ParameterExpression typeParam = Expression.Parameter(typeof(Party));
    Expression propertyValue = Expression.Property(typeParam, typeof(Party).GetProperty("PartyAgents"));
    MethodInfo containsMethod = typeof(List<int>).GetMethod("Contains", new Type[]  typeof(int) );

    List<Expression> expressions = new List<Expression>();
    foreach(int i in partyAgentIds)
    
        Expression containsValue = Expression.Constant(i, typeof(int));
        Expression expression = Expression.Call(propertyValue, containsMethod, containsValue);
        expressions.Add(expression);
    

    Expression body = expressions.First();
    if (expressions.Count() > 1)
           
        for (int i = 1; i < expressions.Count; i++)
         
            Expression right = expressions.ElementAt(i);
            body = Expression.Or(body, right);
        
    

    //    Create the final criteria
    Expression<Func<Party, bool>> criteria = Expression.Lambda<Func<Party, bool>>(
        body,
        new ParameterExpression[]  typeParam );

        //    Now run the query with the criteria
        List<Party> results = _context.Party.Where(criteria).ToList();

注意 - 作为示例提供的基本代码,为了更好地实现,将其分解为几个通用类,以便您可以使用类型 T 以及不同的运算符和属性类型等构建适当的动态表达式。希望它有用:)

【讨论】:

如果你想投反对票,请说明你会如何做得更好;) OP 的查询更加简洁易懂。 OP 遇到问题,因为 EF 没有将查询转换为 SQL。您的代码没有希望作为 SQL 执行。 不同意你的第一点,第二点,也许——我没有用 EF 测试过,因为我没有类似的测试项目。该代码显示了一种不同的方法,如果 OP 将其分解为单独的查询,他可能会获得一些成果。 看看你以前的答案,看起来你知道你的东西,所以我不会过多地谈论这个。我只是不觉得这是你最好的之一。

以上是关于Linq 从一个列表中获取对象,其中其他整数列表包含在第一个列表中的主要内容,如果未能解决你的问题,请参考以下文章

Linq通过搜索关键字从对象的关系列表中选择对象

Linq,EF Core - 按一个字段分组并使用其他字段从其他表中获取数据列表

如何在没有 Linq 的情况下从列表中获取一些对象?

使用Linq获取列表中对象的索引[重复]

使用 Linq 从列表中获取所有匹配值的索引

如何从带有 where 子句的列表中获取数据到另一个列表?