Azure cosmosdb 将创建的文档结果转换为POCO

Azure cosmosdb 将创建的文档结果转换为POCO,azure-cosmosdb,Azure Cosmosdb,我有以下调用DocumentDB并创建新员工文档的代码。然后如何将结果再次转换为员工文档?基本上,我希望捕获创建的文档并将其转换为Employee对象 var result = await client.CreateDocumentAsync(collection.SelfLink, employee); if(result.StatusCode == System.Net.HttpStatusCode.Created) { Employee emp = result.Resource;

我有以下调用DocumentDB并创建新员工文档的代码。然后如何将结果再次转换为员工文档?基本上,我希望捕获创建的文档并将其转换为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?
}
(为stackoverflow社区复制安德鲁·戴维斯的答案,来自)

最简单的方法是让Employee类继承文档,然后将result.Resource强制转换为Employee。若不希望从文档继承,还可以在文档和员工之间定义显式强制转换

如果Employee类的成员的名称与JSON表示的相应属性的名称匹配,那么让Employee类从文档继承应该是现成的

定义您自己的类型转换可以提供更多的控制,可能看起来像这样:

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;
}
公共静态显式操作员员工(文档文档)
{
员工emp=新员工();
emp.Name=doc.GetPropertyValue(“employeeName”);
emp.Number=doc.GetPropertyValue(“EmployeenNumber”);
/*依此类推,适用于员工的所有属性*/
返回emp;
}

这将定义从文档到员工的显式转换。您必须确保GetPropertyValue字符串(和类型参数)与您的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;
}

emp=(动态)result.Resource

我编写了一个扩展方法来实现这一点:

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());
    }
}
公共静态异步任务ReadAsAsync(此文档为d)
{
使用(var ms=new MemoryStream())
使用(var读取器=新的StreamReader(ms))
{
d、 SaveTo(ms);
ms.Position=0;
返回JsonConvert.DeserializeObject(wait reader.ReadToEndAsync());
}
}
然后你可以像这样使用它

Document d;
var myObj = await d.ReadAsAsync<MyObject>();
文件d;
var myObj=wait d.ReadAsAsync();

这里有一个同步扩展方法,它不会悄悄地丢失属性,比如
(动态)
cast方法可以。使用最新的.NET核心功能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);
}
文档文档;//源文件
MyType converted=doc.ConvertTo();
实施:

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);
}
public static T ConvertTo(本文档项)
{
使用var stream=newmemoryStream();
项目.SaveTo(流);
var bytes=new ReadOnlySpan(stream.GetBuffer()).Slice(0,(int)stream.Length);
返回JsonSerializer.Deserialize(字节);
}

是的!他在那里回答了我的问题。我也很感谢您将答案带到这个论坛。这可能在调用CreateDocumentSync时起作用,因为您已经创建了一个员工实例。但如果您还希望能够调用ReadDocumentSync来返回1个对象,则不能将该对象强制转换回Employee。为此,您必须像Arnab的答案一样动态强制转换,或者序列化返回的资源文档。注意继承文档,这里有一个控制台应用程序,您可以使用它来观察奇怪的行为,例如在更改POCO时重复属性被序列化:Gist中的注释显示输出是什么,这是坏消息!谢谢你的提示!太棒了!我似乎找不到关于它实际作用的文档——据我所知,(动态)应该只是禁用类型检查,而不是像这样执行魔术。而且,这意味着我不知道如何在F#中复制它。想法?@Lamarth不知道它为什么有效。另外,还没有在F#上工作过,所以不能说。如果您找到答案,请随时更新答案:)注意结果。如果某些属性与Employee类不匹配,Resource不会引发任何异常。这是Azure Functions 2.0中的CosmosDbTrigger唯一有效的解决方案(除了编写一个巨大的
GetPropertyValue…
方法)。触发器仅适用于一般的
IReadOnlyList输入
,因此您必须自己进行转换。谢谢附录:如果有人遇到与CosmosDbTrigger相同的问题,请在这里分享您的经验:也许它会很快得到解决。这比使用getpropertyvalue要好得多