【问题标题】:Flatten IQueryable from IQueryable<IGrouping<int, object>> to IQueryable<object>将 IQueryable 从 IQueryable<IGrouping<int, object>> 展平为 IQueryable<object>
【发布时间】:2018-05-25 11:08:56
【问题描述】:

我在将 IQueryable&lt;IGrouping&lt;int, object&gt;&gt; 转换为 IQueryable&lt;object&gt; 时遇到问题。

对象是一个属性为int Index的类。
IGrouping's 键就是那个索引。
我想获得一个合并的IQueryable&lt;object&gt;,其中只考虑最低索引。

例如 几个分组与

  • IGrouping&lt;3, object&gt;
  • IGrouping&lt;4, object&gt;
  • IGrouping&lt;4, object&gt;
  • IGrouping&lt;5, object&gt;
  • IGrouping&lt;6, object&gt;
  • IGrouping&lt;3, object&gt;
  • IGrouping&lt;3, object&gt;

结果应该是IQueryable&lt;object&gt;,其中只有索引为 3 的对象在里面。

P.S 我需要一个 IQueryable 来对其执行 DateTime DbFunctions。所以希望这可以通过一个 SQL 查询来完成。

【问题讨论】:

  • 你是怎么用同一个键得到多个IGroupings的?
  • 您的问题不清楚且范围广泛。不清楚:查看分组的IQueryable来源会有所帮助,否则根本无法判断是否可以继续为IQueryable。广泛:您没有表现出自己的努力,因此很难看出您具体需要帮助的地方。

标签: c# entity-framework linq-to-sql


【解决方案1】:

要按所述扁平化组,您需要:

  1. 按索引对每个组内的对象进行排序
  2. 从每个组中获取第一个顶部对象

此代码示例演示了LINQ 查询:

IQueryable<MyObject> objects = new[]
{
    new MyObject{ GroupId = 3, Index = 31, OtherProperty = "Group 3 / Index 31" },
    new MyObject{ GroupId = 3, Index = 32, OtherProperty = "Group 3 / Index 32" },
    new MyObject{ GroupId = 3, Index = 32, OtherProperty = "Group 3 / Index 32" },
    new MyObject{ GroupId = 4, Index = 43, OtherProperty = "Group 4 / Index 43" },
    new MyObject{ GroupId = 4, Index = 42, OtherProperty = "Group 4 / Index 42" },
    new MyObject{ GroupId = 4, Index = 45, OtherProperty = "Group 4 / Index 45" },
    new MyObject{ GroupId = 4, Index = 46, OtherProperty = "Group 4 / Index 46" },
    new MyObject{ GroupId = 5, Index = 51, OtherProperty = "Group 5 / Index 51" },
    new MyObject{ GroupId = 5, Index = 54, OtherProperty = "Group 5 / Index 54" },
    new MyObject{ GroupId = 6, Index = 67, OtherProperty = "Group 6 / Index 67" },
    // ...                                                                    
    new MyObject{ GroupId = 6, Index = 63, OtherProperty = "Group 6 / Index 63" }
}.AsQueryable();

IQueryable<IGrouping<int, MyObject>> groups = objects.GroupBy(o => o.GroupId);

IQueryable<MyObject> outcome = groups.Select(grouping => grouping.OrderBy(g => g.Index).First());

List<MyObject> outcomeList = outcome.ToList();

// outcomeList contains: 
// new MyObject{ GroupId = 3, Index = 31, OtherProperty = "Group 3 / Index 31" };
// new MyObject{ GroupId = 4, Index = 42, OtherProperty = "Group 4 / Index 42" };
// new MyObject{ GroupId = 5, Index = 51, OtherProperty = "Group 5 / Index 51" };
// new MyObject{ GroupId = 6, Index = 63, OtherProperty = "Group 6 / Index 63" };

【讨论】:

    【解决方案2】:

    您可以使用OrderBy 对您的组进行排序,然后使用FirstOrDefault 获取第一组

    var firstGroup = list.GroupBy(x => x.Index)
      .OrderBy(g => g.Key)
      .FirstOrDefault()
      .AsQueryable();
    

    请查看example

    【讨论】:

    • 我使用 linq-to-sql,需要 IQueryable 而不是 IEnumerable
    • @Muarl 请查看我的编辑。我已经用 linqPad 和我的数据库对其进行了测试。它产生两个 sql 查询:首先获取最小键,其次获取具有该键的所有记录
    • 很遗憾没有,这里的问题是 FirstOrDefault 调用,另外我想可以通过 1 个 sql 查询来实现这一点
    【解决方案3】:

    其实我终于找到了合适的解决方案。 以前的答案的问题总是First() 电话。

    list.Where(SomeFilterExpression)
        .GroupBy(e => e.Index)
        .OrderBy(g => g.Key)
        .Take(1)
        .SelectMany(g => g.Select(e => e))
        .Where(SomeAdditionalFilterExpression)
        .ToList()
    

    这段代码(尤其是Take() 帮助我仅使用一个 SQL 查询来解决我的问题) 无论如何感谢您的专业知识。

    【讨论】:

      【解决方案4】:

      多选

      将变平,然后您可以再次按结果排序并按结果排序。但是对于 Groups 中的项目返回单个结果集 SelectMany 是有

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-29
        • 2011-01-29
        • 2012-01-07
        • 1970-01-01
        • 2023-03-27
        • 1970-01-01
        相关资源
        最近更新 更多