如何使用 Linq for Cosmos noSQL 展平嵌套结构中的某些属性?

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

(代码详细信息在问题末尾...)

我有一个 3 级数据结构,例如

top.Middles[y].Bottoms[z].Secret
,我想要一个包含最内部秘密为“禁止”的所有外层、中层和底层的列表。在 SQL 中我会将其表达为...

SELECT t.id topId, m.id as middleId, b.id as bottomId
FROM Tops t
join m in t.Middles
join b IN m.Bottoms
where b.Secret = 'Forbidden'

这给了我类似的东西

[
{ "topId": "296f9023-f150-45cd-ad38-a7be2ac83f41", "middleId": "101c24bc-71cb-4b6b-a6cf-6979be61be45", "bottomId": "812ac30c-79d4-4c62-94c2-a8cd3eb19bb6" },
{ "topId": "296f9023-f150-45cd-ad38-a7be2ac83f41", "middleId": "101c24bc-71cb-4b6b-a6cf-6979be61be45", "bottomId": "9b298db2-db68-4a0c-82f4-d5bd270aa72b" },
{ "topId": "296f9023-f150-45cd-ad38-a7be2ac83f41", "middleId": "350f63eb-e41a-493f-9e6d-740818242b7e", "bottomId": "56a51a6c-4e6b-4c52-bbc7-0d71b2486c76" },
{ "topId": "1ebdb15f-5864-4e1e-860d-e3a97696da38", "middleId": "ce3bb505-5412-4368-a30e-7f6ce7838a95", "bottomId": "093c7d30-97bb-4fcf-9bd7-0814cbb92571" },
{ "topId": "1ebdb15f-5864-4e1e-860d-e3a97696da38", "middleId": "1b239750-1a91-4f0c-9fb1-b1d9e333349e", "bottomId": "b7c27305-59a3-4af9-93ed-5ca272472d37" },
{ "topId": "1ebdb15f-5864-4e1e-860d-e3a97696da38", "middleId": "a70b3933-3cde-44d0-80a8-fef6d958ce4a", "bottomId": "30c74577-ef59-41ec-8fd2-0ded3f3c30a2" }
]

这符合我的目的...

但我更愿意使用 LINQ 来完成此操作,这样我就可以对属性名称获得强大的类型和编译器意识。

代码存在各种编译器错误,我无法弄清楚这一点。方法名称是

Example.GetTopsContainingTheSecretWord

var topsContainingTheSecretWord = new Example().GetTopsContainingTheSecretWord("Forbidden");

代码

public class Outer
{
    public string id { get; set; }
    public string Name { get; set; }
    public List<Middle> Middles { get; set; }
}

public class Middle
{
    public string id { get; set; }
    public string Name { get; set; }
    public List<Inner> Inners { get; set; }
}

public class Inner
{
    public string id { get; set; }
    public string Secret { get; set; }
    public string Name { get; set; }
}

public record ResultRecord(
    Guid TopId,
    Guid MiddleId,
    Guid BottomId
);

public class Example {
    public async Task<List<ResultRecord>> GetTopsContainingTheSecretWord(
        string secretWord,
        CancellationToken cancellationToken = default
    )
    {
        var query = _plansContainer.GetItemLinqQueryable<ResultRecord>(true)
            .SelectMany(t => t.Middles)
            .SelectMany(m => m.Bottoms.Where(b => b.Secret == secretWord))
            .ToFeedIterator();

        var results = new List<ResultRecord>();
        while (query.HasMoreResults)
        {
            var response = await query.ReadNextAsync();
            results.AddRange(response);
        }

        return results;
    }
}
azure azure-cosmosdb azure-cosmosdb-sqlapi
1个回答
0
投票

您将无法使用 linq 生成精确的查询,但可以获得相同的结果。例如,我使用了您的模型,但将 id 更改为

Guid
,只要您始终使用 guid 作为标识符,它就应该有效。

var feed = container
    .GetItemLinqQueryable<Outer>()
    .SelectMany(t => t.Middles.Select(m => new { t, m }))
    .SelectMany(x => x.m.Inners.Select(i => new { x.t, x.m, i }))
    .Where(x => x.i.Secret == "Forbidden")
    .Select(x => new
    {
        BottomId = x.i.id,
        MiddleId = x.m.id,
        TopId = x.t.id,
    })
    .ToFeedIterator();

List<ResultRecord> results = [];

while (feed.HasMoreResults)
{
    foreach (var item in await feed.ReadNextAsync())
    {
        results.Add(new ResultRecord(item.TopId, item.MiddleId, item.BottomId));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.