SelectMany 中的 SelectMany 和 DefaultIfEmpty 工作错误

问题描述 投票:0回答:1

我想获取按已链接查询的 desc 订购的请求项目的所有子项。当我尝试在另一个 SelectMany 中使用带有 DefaultIfEmpty 的 SelectMany 时:

DbSet<MyRecord<long>>().FromSql(select * from unnest({0}), object[] { NpgsqlParameter<MyRecord<long>[]> })
.SelectMany(pk => dataContext.TestItems
    .Where(item => pk.Item == item.ParentId)
    .SelectMany(
        collectionSelector: entity => dataContext.TestQueries
            .Where(a => a.QueryId == entity.EntityId)
            .DefaultIfEmpty(), 
        resultSelector: (left, right) => new JoinResult<TestItem, TestQuery>{ 
            Left = left, 
            Right = right 
        }
    )
    .OrderByDescending(result => result.Right.ObjectId)
    .Select(result => result.Left))

与实体

class MyRecord<T>
{
    public T Item {get;set;}
}
class JoinResult<T1, T2>
{
    public T1 Left { get; set; }
    public T2 Right { get; set; }
}
class  TestItem
{
    public int EntityId {get;set;}
    public string Name {get;set;}
    public int ParentId {get;set;} // link to TestItem.EntityId
}
class  TestQuery
{
    public int QueryId {get;set;}
}

我得到sql查询:

SELECT t0.EntityId, t0.Name, t0.ParentId
FROM (
    select * from unnest(ARRAY[101,102])
) AS e
LEFT JOIN LATERAL (
    SELECT c.EntityId, c.Name, c.ParentId
    FROM items AS c
    JOIN LATERAL (
        SELECT s.QueryId
        FROM queries AS q
        WHERE q.QueryId = c.EntityId
    ) AS t ON TRUE
    WHERE e.unnest = c.ParentId
    ORDER BY t.QueryId DESC
) AS t0 ON TRUE

但我希望在 CROSS JOIN 中使用 LEFT JOIN。如何停止第一个 SelectMany 上的转换查询并获取 smh:

SELECT t0.EntityId, t0.Name, t0.ParentId
FROM (
    select * from unnest(ARRAY[101,102])
) AS e
JOIN LATERAL (
    SELECT c.EntityId, c.Name, c.ParentId
    FROM items AS c
    LEFT JOIN LATERAL (
        SELECT s.QueryId
        FROM queries AS q
        WHERE q.QueryId = c.EntityId
    ) AS t ON TRUE
    WHERE e.unnest = c.ParentId
    ORDER BY t.QueryId DESC
) AS t0 ON TRUE

我认为 DefaultIfEmpty 将 SelectMany 设置为 LEFT JOIN 但翻译必须在内部扩展上。如何更改查询以获得此签名上的预期 sql?

我尝试使用 GroupJoin,但此功能破坏了许多现有逻辑,因此我认为无法访问。 我们所有的构建都在 .net 6 和 8 中重复了这种行为

c# entity-framework linq
1个回答
0
投票

您的代码在语法上不太正确,我不得不假设您的意图。

您的主要问题是,当您只想订购内部子查询时,您正在订购外部查询。

还有:

  • 如果您有导航,则无需加入。只需使用
    .Include
  • 您不需要实体来创建单列的原始查询。您可以使用
    context.Database.SqlQuery
    来代替。
dataContext.Database.SqlQuery<long>($"select * from unnest({ new NpgsqlParameter("@items", listHere) })")
    .SelectMany(pk => dataContext.TestItems
        .Where(item => pk.Item == item.ParentId)
        .Include(entity => dataContext.TestQueries
            .OrderByDescending(result => result.Right.ObjectId)
        )
        .DefaultIfEmpty()
    )
© www.soinside.com 2019 - 2024. All rights reserved.