Нужно ли мне десериализовать результат запроса из DocumentDb?

У меня есть простой объект POCO для человека, который выглядит так:

public class Person
{
   public int PersonId {get; set;}
   public string FirstName {get; set;}
   public string MiddleName {get; set;}
   public string LastName {get; set;}
   public char Gender {get; set;}
}

У меня есть следующий код, который запрашивает коллекцию People в моей базе данных DocumentDb.

private async static Task<List<Person>> GetPeopleList(string colSelfLink)
{
   dynamic doc = client.CreateDocumentQuery<Document>(colSelfLink, "SELECT p.PersonId, p.FirstName, p.MiddleName, p.LastName, p.Gender FROM People p").AsEnumerable().FirstOrDefault();
   List<Person> peopleList = new List<Person>();
   if (doc != null)
   {
      peopleList = doc;
   }
   return peopleList;
}

Когда я запускаю этот код, я получаю следующую ошибку:

Невозможно десериализовать текущий объект JSON (например, {"name":"value"}) в тип "System.Collections.Generic.List`1[MyApp.Person]", поскольку для этого типа требуется массив JSON (например, [1,2, 3]) для правильной десериализации. Чтобы исправить эту ошибку, либо измените JSON на массив JSON (например, [1,2,3]), либо измените десериализованный тип, чтобы он был обычным типом .NET (например, не примитивный тип, такой как целое число, а не тип коллекции, такой как массив или список), который можно десериализовать из объекта JSON. JsonObjectAttribute также можно добавить к типу, чтобы заставить его десериализоваться из объекта JSON. Путь «PersonId», строка 1, позиция 48.

Как преобразовать объект JSON, полученный из моего запроса, в объект Person? В моем приложении MVC связыватель модели неплохо справляется со своей задачей, но он выполняется в отдельной библиотеке классов. Как мне подойти к преобразованию этого объекта JSON?


person Sam    schedule 05.09.2014    source источник
comment
FirstOrDefault() возвращает один объект (или null). Его результат не может быть назначен списку.   -  person Anthony Chu    schedule 05.09.2014
comment
Я понимаю вашу точку зрения, поэтому я изменил FirstOrDefault() на ToList(), но проблема все еще остается. Теперь я получаю сообщение «Невозможно неявно преобразовать тип System.Collections.GenericList‹Microsoft.Azure.Documents.Document›» в «System.Collections.GenericList‹MyApp.Person›». Как мне справиться с конверсией? Нужно ли иметь foreach и обрабатывать преобразование каждого документа в объект Person? Я тоже так пробовал, но не получилось.   -  person Sam    schedule 05.09.2014
comment
Думаю, я понял. Похоже, мне нужно выполнить цикл foreach и десериализовать объект document/json в мой класс POCO. Это правильный подход? Это сработало для меня, но я хочу убедиться, что нет лучшего способа сделать это.   -  person Sam    schedule 05.09.2014
comment
Я еще не использовал DocumentDb, но я думаю, что это все, что вам нужно? List<Person> peopleList = client.CreateDocumentQuery<Person>(colSelfLink, "...").AsEnumerable().ToList();   -  person Anthony Chu    schedule 05.09.2014


Ответы (3)


Это то, что я сделал, и это работает. Я был бы признателен за другие ответы, если есть лучший способ.

private async static Task<List<Person>> GetPeopleList(string colSelfLink)
{
   dynamic doc = client.CreateDocumentQuery<Document>(colSelfLink, "SELECT p.PersonId, p.FirstName, p.MiddleName, p.LastName, p.Gender FROM People p").AsEnumerable().ToList();
   List<Person> peopleList = new List<Person>();
   if (doc != null)
   {
      Person person;
      foreach(var item in doc)
      {
         person = JsonConvert.DeserializeObject<Person>(item.ToString());
         peopleList.Add(person);
      }
   }
   return peopleList;
}
person Sam    schedule 05.09.2014
comment
Лучшее, что я нашел. Я играл с десятками разных способов и ничего не получалось. - person ThinkingStiff; 09.10.2015
comment
Я тоже так делал, но пока воздерживаюсь от этого. Проблема с .ToString() заключается в том, что вы зависите от переопределения (или нет) класса ресурсов DocumentDB SDK над .ToString(). Что может послужить вам лучше, так это сначала JsonConvert.SerializeObject(item), а затем десериализовать его в свой POCO. - person ethane; 23.07.2018

Энтони Чу был на правильном пути с этим. Простое решение:

private async static Task<List<Person>> GetPeopleList(string colSelfLink)
{
   return client.CreateDocumentQuery<Person>(colSelfLink, "SELECT * FROM People").ToList();
}

Это автоматически десериализует каждую возвращенную запись и превратит ее в объект People.

person Richard Laxton    schedule 15.10.2014
comment
что делать, если в коллекции несколько форматов документов? вполне возможно, учитывая, что в коллекциях Cosmos db, по сути, просто ведра для документов. - person m1nkeh; 20.02.2018

У меня была точно такая же проблема, только мой список сбойных объектов был вложен в другой объект (документ).

public List<MyObject> MyProperty { get; set; }

Я так счастлив, что нашел решение:

Если в вашем документе есть списки сложных объектов, поместите это в свойства сложного объекта:

[JsonProperty(PropertyName = "yourPropertyName")]

Хорошо известно, что это необходимо для основного объекта (документа), однако они не нужны для вложенных объектов, пока они не будут в списке.

person right_there    schedule 22.11.2015