使用 EF Core Azure Cosmos DB 提供程序中的非结构化数据Working with Unstructured Data in EF Core Azure Cosmos DB Provider
EF Core 旨在使使用在模型中定义的架构的数据变得简单。 但 Azure Cosmos DB 的优点之一是存储数据形状的灵活性。
访问原始 JSONAccessing the raw JSON
可以通过名为 "__jObject"
的卷影状态中 JObject
包含表示从存储区接收的数据的特定属性来访问不 EF Core 跟踪的属性,以及将存储的数据:
using (var context = new OrderContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var order = new Order
{
Id = 1,
ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" },
PartitionKey = "1"
};
context.Add(order);
await context.SaveChangesAsync();
}
using (var context = new OrderContext())
{
var order = await context.Orders.FirstAsync();
var orderEntry = context.Entry(order);
var jsonProperty = orderEntry.Property<JObject>("__jObject");
jsonProperty.CurrentValue["BillingAddress"] = "Clarence House";
orderEntry.State = EntityState.Modified;
await context.SaveChangesAsync();
}
using (var context = new OrderContext())
{
var order = await context.Orders.FirstAsync();
var orderEntry = context.Entry(order);
var jsonProperty = orderEntry.Property<JObject>("__jObject");
Console.WriteLine($"First order will be billed to: {jsonProperty.CurrentValue["BillingAddress"]}");
}
{
"Id": 1,
"PartitionKey": "1",
"TrackingNumber": null,
"id": "1",
"Address": {
"ShipsToCity": "London",
"ShipsToStreet": "221 B Baker St"
},
"_rid": "eLMaAK8TzkIBAAAAAAAAAA==",
"_self": "dbs/eLMaAA==/colls/eLMaAK8TzkI=/docs/eLMaAK8TzkIBAAAAAAAAAA==/",
"_etag": "\"00000000-0000-0000-683e-0a12bf8d01d5\"",
"_attachments": "attachments/",
"BillingAddress": "Clarence House",
"_ts": 1568164374
}
警告
"__jObject"
属性是 EF Core 基础结构的一部分,只应用作最后的手段,因为在将来的版本中可能会有不同的行为。
备注
对实体所做的更改将覆盖 SaveChanges
期间 "__jObject"
中存储的值。
使用 CosmosClientUsing CosmosClient
若要完全分离 EF Core 获取 DbContext
中AZURE COSMOS DB SDK 的一部分的CosmosClient对象:
using (var context = new OrderContext())
{
var cosmosClient = context.Database.GetCosmosClient();
var database = cosmosClient.GetDatabase("OrdersDB");
var container = database.GetContainer("Orders");
var resultSet = container.GetItemQueryIterator<JObject>(new QueryDefinition("select * from o"));
var order = (await resultSet.ReadNextAsync()).First();
Console.WriteLine($"First order JSON: {order}");
order.Remove("TrackingNumber");
await container.ReplaceItemAsync(order, order["id"].ToString());
}
缺少属性值Missing property values
在上面的示例中,我们从顺序中删除了 "TrackingNumber"
属性。 由于在 Cosmos DB 中索引的工作原理,引用缺少的属性的其他位置的查询可能会返回意外的结果。 例如:
using (var context = new OrderContext())
{
var orders = await context.Orders.ToListAsync();
var sortedOrders = await context.Orders.OrderBy(o => o.TrackingNumber).ToListAsync();
Console.WriteLine($"Number of orders: {orders.Count}");
Console.WriteLine($"Number of sorted orders: {sortedOrders.Count}");
}
排序的查询实际上不返回任何结果。 这意味着,当直接使用存储时,应注意始终填充由 EF Core 映射的属性。
备注
在未来版本的 Cosmos 中,此行为可能会发生变化。 例如,当前如果索引策略定义了复合索引 {Id/? ASC,TrackingNumber/? ASC)},则为 “ORDER BY c.Id ASC,ASC” 的查询__将__返回缺少 "TrackingNumber"
属性的项。