【问题标题】:I can not retrieve a list of objects from CosmosDb document我无法从 CosmosDb 文档中检索对象列表
【发布时间】:2021-06-16 10:55:02
【问题描述】:

我在使用 ComsosDb .NET SDK 3 的 SQL 查询时出错。我想从文档中请求对象列表。 这是我存储在 CosmosDb 中的文档(fid 是分区键):

{
    "id": "1abc",
    "fid": "test",
    "docType": "Peeps",
    "People": [
        {
            "Name": "Bill",
            "Age": 99
        },
        {
            "Name": "Marion",
            "Age": 98
        },
        {
            "Name": "Seb",
            "Age": 97
        }
    ],
    "_rid": "mo53AJczKUuL9gMAAAAAAA==",
    "_self": "dbs/mo53AA==/colls/mo53AJczKUs=/docs/mo53AJczKUuL9gMAAAAAAA==/",
    "_etag": "\"9001cbc7-0000-1100-0000-60c9d58d0000\"",
    "_attachments": "attachments/",
    "_ts": 1623840141
}

我的结果显示项目计数为 1,属性设置为默认值 - 名称为空,年龄为 0。 我期待一个 IEnumerable 3 人。代码如下:

class MyPeople
{
   public IEnumerable<Person> People { get; set; }
}

class Person
{
   public string Name { get; set; }
   public int Age { get; set; }
}

[Fact]
public async Task CosmosPeopleTest_ReturnsThreePeople()
{
   var config = GetConFig();
   var cosmosClientV2 = new CosmosClient(config["Cosmos:ConnectionString"]);
   var container = cosmosClientV2.GetContainer(config["Cosmos:DbName"], config["Cosmos:Collectionname"]);
   var sql = "SELECT c.People FROM c WHERE c.docType = 'Peeps'";
            QueryDefinition queryDefinition = new QueryDefinition(sql);
   var results = new List<Person>();
   FeedIterator<Person> q = container.GetItemQueryIterator<Person>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });
   while (q.HasMoreResults)
   {
       var x = await q.ReadNextAsync();
       results.AddRange(x.ToList());
   }
   Assert.Equal(3, results.Count);
}

如果我将查询更改为

 sql = "SELECT c.People FROM c JOIN d IN c.People";

我有三个人,它们都具有默认属性名称和年龄。

【问题讨论】:

  • 您缺少一个根类。你得到的根对象不是一个人,而是 MyPeople。
  • 我相信您的类型有问题。 SELECT c.People 返回 Person 的列表,您的代码直接迭代 Persons 而不是“Persons 的列表”。由于它使用重构,它创建了一个Person 对象但无法填充其属性
  • 很遗憾,我无法正确获取代码。

标签: c# azure-cosmosdb


【解决方案1】:

您的类型有问题。 SELECT c.People以这种形式返回一个对象:

{
   People: [
      ...
   ]
}

当您使用此代码进行迭代时

FeedIterator<Person> q = container.GetItemQueryIterator<Person>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });

CosmosDB 尝试将每个结果对象(如上)“转换”为Person 类。但它为此使用反射。因此它创建了一个 Person 对象,但没有找到任何字段来填充其属性 - 它不会失败,但会创建所有属性都使用默认值初始化的空对象。

所以要解决它,您需要使用MyPeople 而不是Person

FeedIterator<MyPeople> q = container.GetItemQueryIterator<MyPeople>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });

由于MyPeople是返回对象的正确形式,它将能够读取CosmosDB返回的对象并使用它们。

完整的工作代码:

var config = GetConFig();
var cosmosClientV2 = new CosmosClient(config["Cosmos:ConnectionString"]);
var container = cosmosClientV2.GetContainer(config["Cosmos:DbName"], config["Cosmos:Collectionname"]);
var sql = "SELECT c.People FROM c WHERE c.docType = 'Peeps'";
QueryDefinition queryDefinition = new QueryDefinition(sql);
var results = new List<Person>();
FeedIterator<MyPeople> q = container.GetItemQueryIterator<MyPeople>(queryDefinition, null, new QueryRequestOptions { PartitionKey = new PartitionKey("test") });
while (q.HasMoreResults)
{
   var x = await q.ReadNextAsync();
   var myPeopleRes = x.Resource;

   foreach (var people in myPeopleRes)
   {
       results.AddRange(people.People);
   }
}
Assert.Equal(3, results.Count);

【讨论】:

  • 所以你必须返回整个文档然后提取 List ?有没有办法只返回 List
  • 它不是返回整个文档,而是一个只有People 字段而没有其他内容的对象,与MyPeople 完全一样。例如,您将无法读取 docType 等其他字段
猜你喜欢
  • 1970-01-01
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多