在 C# 中使用 LINQ to SQL 查询 Cosmos DB 中的动态键嵌套字典结构

Query a dynamic-key nested dictionary structure in Cosmos DB with LINQ to SQL in C#

我想查询 dynamic-key 嵌套字典结构中的值,以便使用 LINQ 将权限过滤器应用于 SQL(最好使用索引查询和不会导致扫描)。

我的 JSON 结构包含一个 Permissions 属性,它基本上只是一个 C# dictionary<string, dictionary<string, dictionary<string, string>>>

JSON 示例:

{
    "Permissions": {
        "Account 1 GUID": {
            "Location": "Location1 GUID"
        },
        "Account 2 GUID: {
            "Location": "Location 2 GUID"
        },
        "Account 3 GUID": {
            "Location": "Location 3 GUID"
        }
    }
}

帐户密钥属性是动态的,这意味着它们实际上是拥有嵌套位置的帐户的 GUID。

执行查询时,我有一个位置和帐户 ID 列表,应该使用这些 ID 来执行权限过滤,只授予对这些位置的访问权限。

我想应用的过滤查询是类似于某些东西,就像这样(这就是我想要实现的):

var allowedLocations = new List<string> { "Location 1 GUID", "Location 2 GUID" };

var result = AllDocsIQueryable.Where(model => 
    model.Permissions.Values.Where(secondLevel =>
        secondLevel.Values.Where(thirdLevel =>
            allowedLocations.Contains(thirdLevel)))).ToList();

如您所见,我想通过查询包含我的访问列表中任何位置 ID 的文档,将用户可以查看的文档过滤为用户定义了访问权限的文档。

我不知道如何构建查询这样的结构的查询。我尝试了 .Select.SelectMany 查询的多种组合,但我没有尝试成功,所有我尝试的都没有结果或失败。

查询以下会产生正确的结果,但我真的很想避免必须使用谓词生成器动态构建此查询,例如:

var result = AllDocsIQueryable.Where(model => 
    (model.Permissions["Account 1 GUID"]["Location"].IsDefined() &&
    model.Permissions["Account 1 GUID"]["Location"] == "Location 1 GUID")
    ||
    (model.Permissions["Account 2 GUID"]["Location"].IsDefined() &&
    model.Permissions["Account 2 GUID"]["Location"] == "Location 2 GUID")
    // .. etc ..
    ).ToList();

我希望我的问题很清楚,并且有一个 LINQ to SQL/Cosmos/NoSQL/C# super wiz 可以帮助我构建这个查询?也许有人知道我根本无法构造这个查询,我需要更改 JSON 结构(我知道这会更好)?我需要使用 LINQ 进行查询而不是 SQL 查询字符串!

结论:

看来,就像我担心的那样,没有办法构建查询。

据我所知,并已尝试和阅读,如果不将动态帐户密钥构建到查询中,就无法做到这一点。

我已将架构更改为包含数组。

"Permissions": [
    {
        "LocationId": "Loc1",
        "AccountId": "Acc1"
    },
    {
        "LocationId": "Loc2",
        "AccountId": "Acc2"            
    }
]

恐怕仅使用 LINQ 是无法实现的。以下是您的选择:

  • 使用 UDF 从权限对象中检索位置数组。不幸的是,您不能从 LINQ 调用 UDF(至少在 SDK v3 中不能——在 SDK v2 中您 可以 ),因此您需要使用原始 SQL。 (实际上有 hacky 方法。)这个解决方案很糟糕,因为它真的很慢。

  • 保留您的模式,但引入额外的 属性,其中包含嵌套在您的权限对象中的位置列表。现在你可以轻松使用LINQ,而且查询速度很快。