Преобразование результата созданного документа в POCO

У меня есть следующий код, который вызывает DocumentDB и создает новый документ Employee. Как мне снова преобразовать результат в документ сотрудника? По сути, я хочу захватить созданный документ и преобразовать его в объект Employee.

var result = await client.CreateDocumentAsync(collection.SelfLink, employee);

if(result.StatusCode == System.Net.HttpStatusCode.Created)
{
   Employee emp = result.Resource; // How do I convert the result to Employee object here?
}

person Sam    schedule 25.11.2014    source источник


Ответы (4)


(Копирование ответа Эндрю Дэвиса с форумов DocumentDB MSDN для сообщества stackoverflow)

Самый простой способ — наследовать класс Employee от Document, а затем преобразовать result.Resource в Employee. Если вы не хотите наследовать от Document, вы также можете определить явное приведение между Document и Employee.

Наследование класса Employee от Document должно работать по умолчанию, если имена членов вашего класса Employee совпадают с именами соответствующих свойств представления JSON.

Определение собственного преобразования типов дает вам больше контроля и может выглядеть примерно так:

public static explicit operator Employee(Document doc)
{
    Employee emp = new Employee();
    emp.Name = doc.GetPropertyValue<string>("employeeName");
    emp.Number = doc.GetPropertyValue<int>("employeeNumber");
    /* and so on, for all the properties of Employee */
    return emp;
}

Это определило бы явное приведение от Document к Employee. Вам нужно будет убедиться, что строки GetPropertyValue (и аргументы типа) соответствуют вашим свойствам JSON.

person Andrew Liu    schedule 25.11.2014
comment
Ага! Там он ответил на мой вопрос. Я также ценю ваш ответ на этот форум. - person Sam; 26.11.2014
comment
Это может работать при вызове CreateDocumentAsync, поскольку вы уже создали экземпляр Employee. Но если вы также хотите иметь возможность вызывать ReadDocumentAsync для возврата 1 объекта, вы не можете привести это обратно к сотруднику. Для этого вам нужно выполнить динамическое приведение, например, ответ Арнаба, или сериализовать возвращенный ресурсный документ. - person Andy; 27.01.2017
comment
Остерегайтесь наследования Document, вот консольное приложение, которое вы можете использовать для наблюдения за странным поведением, например сериализацией повторяющихся свойств при внесении изменений в ваш POCO: gist.github.com/Jacob-McKay/cd44a7339a329d763728348f43917db0 комментарии в Gist показывают результат, это плохие новости! - person Jacob McKay; 13.04.2018

Вы можете сделать динамическое приведение следующим образом:

Employee emp = (dynamic)result.Resource;

person Arnab Chakraborty    schedule 04.12.2014
comment
Спасибо за этот совет! - person Samurai Ken; 10.02.2016
comment
Это фантастично! Кажется, я не могу найти документацию о том, что это на самом деле делает - насколько я могу судить, (динамический) должен просто отключать проверку типов, а не выполнять подобную магию. Кроме того, это означает, что я понятия не имею, как воспроизвести это на F#. Идеи? - person Lamarth; 21.02.2017
comment
@ Ламарт Не уверен, почему это работает. Кроме того, я не работал над F #, поэтому не могу сказать. Не стесняйтесь обновлять ответ, если вы это понимаете :) - person Arnab Chakraborty; 23.02.2017
comment
обратите внимание, что result.Resource не будет генерировать никаких исключений, если некоторые свойства не совпадают с классом Employee. - person GorvGoyl; 18.04.2017

Я написал метод расширения, чтобы сделать это:

public static async Task<T> ReadAsAsync<T>(this Document d)
{
    using (var ms = new MemoryStream())
    using (var reader = new StreamReader(ms))
    {
        d.SaveTo(ms);
        ms.Position = 0;
        return JsonConvert.DeserializeObject<T>(await reader.ReadToEndAsync());
    }
}

Затем вы можете использовать его как

Document d;
var myObj = await d.ReadAsAsync<MyObject>();
person mdickin    schedule 08.11.2017
comment
Это единственное работающее решение (кроме написания огромного метода GetPropertyValue...), когда речь идет о CosmosDbTrigger в Функциях Azure 2.0. Триггер работает только с общим IReadOnlyList<Document> input, поэтому вы должны выполнить преобразование самостоятельно. Спасибо! - person Squiggle; 22.10.2018
comment
Дополнение: если у кого-то возникла такая же проблема с CosmosDbTrigger, поделитесь своим опытом здесь: github.com/Azure/azure-webjobs-sdk-extensions/issues/389 и, возможно, проблема будет решена раньше - person Squiggle; 22.10.2018
comment
это намного лучше, чем использование getpropertyvalue - person Anil Purswani; 07.03.2019

Вот синхронный метод расширения, который не пропускает свойства молча, как это может делать метод (dynamic) cast. Использует последние функции .NET Core Span и System.Text.Json для повышения производительности.

Использование:

Document doc; // source Document
MyType converted = doc.ConvertTo<MyType>();

Реализация:

public static T ConvertTo<T>(this Document item)
{
    using var stream = new MemoryStream();
    item.SaveTo(stream);
    var bytes = new ReadOnlySpan<byte>(stream.GetBuffer()).Slice(0, (int)stream.Length);
    return JsonSerializer.Deserialize<T>(bytes);
}
person Noah Stahl    schedule 10.08.2020