【问题标题】:Query a dynamic-key nested dictionary structure in Cosmos DB with LINQ to SQL in C#在 C# 中使用 LINQ to SQL 查询 Cosmos DB 中的动态键嵌套字典结构
【发布时间】:2020-11-25 10:20:38
【问题描述】:

我想查询 dynamic-key 嵌套字典结构中的值,以便使用 LINQ to 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 查询的组合,但我尝试过的都没有成功,我尝试过的所有方法都没有结果或失败。

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

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# 超级向导可以帮助我构建这个查询?也许有人知道我根本无法构造这个查询,我需要更改 JSON 结构(我知道这会更好)?我需要使用 LINQ 而不是 SQL 查询字符串进行查询!

结论:

正如我所担心的那样,似乎无法构建查询。

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

我已更改架构以包含数组。

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

【问题讨论】:

  • 您的问题不清楚。您提供的 LINQ 查询甚至没有编译,那么您为什么声称它没有产生任何结果?为什么您仅针对“帐户 1 GUID”检查“位置 1 GUID”而仅针对“帐户 2 GUID”检查“位置 2 GUID”?请完全准确地说明您要达到的目标。另外,请说明您是否必须使用 LINQ,或者您是否还可以构造 SQL 查询字符串。
  • @MoB。我已经编辑并试图澄清这个问题。 1) 我要应用的过滤查询类似于这样: 2) 我需要使用 LINQ 进行查询,而不是SQL 查询字符串! 3) 我知道位置 ID 所在的帐户 ID。我不明白您的问题?我想只过滤允许列表中的任何位置命中,正如您在示例查询中看到的那样,我希望 LIKE 能够使用!我认为我实际上对我想要实现的目标非常精确,但我已经大胆地说明了我需要什么!
  • 抱歉,目前还不清楚。您的 LINQ 查询没有任何意义。所以基本上你忽略了帐户 ID,只是想检查文档的权限对象中是否包含任何给定的位置 ID 集?
  • 可以更改文档结构吗?然后您可以将帐户ID存储在属性“accountId”中,权限将是一个数组,查询将非常简单。
  • @MoB。对,就是这样!这就是我想要实现的!在第二个查询中,我说明了如何使用帐户 ID GUID,我可以实现产生正确结果的查询。但是,我注意到我不想那样做,因为我需要动态构建(相当大的)查询,对吧?

标签: c# json .net linq-to-sql azure-cosmosdb


【解决方案1】:

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

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

  • 保留您的架构,但引入一个附加属性,其中包含嵌套在您的权限对象中的位置列表。现在您可以轻松使用LINQ,而且查询速度很快。

【讨论】:

  • 是的! UDF 也不是我想走的路线!据我所知,并且已经尝试和阅读,如果不将动态帐户密钥构建到查询中,就没有办法做到这一点 - 这是我已经拥有和工作的。我已经将架构更改为包含数组,而只需要咬苹果并进行完整迁移...
猜你喜欢
  • 2019-01-25
  • 1970-01-01
  • 2020-06-15
  • 2012-11-07
  • 2021-12-14
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
相关资源
最近更新 更多