Uso di dati non strutturati nel provider Azure Cosmos DB di EF Core

EF Core è stato progettato per semplificare l'uso dei dati che seguono uno schema definito nel modello. Tuttavia, uno dei punti di forza di Azure Cosmos DB è la flessibilità nella forma dei dati archiviati.

Accesso al codice JSON non elaborato

Annotazioni

La "__jObject" proprietà shadow è stata rimossa in EF Core 11. Per informazioni dettagliate, vedere Modifiche di rilievo in EF Core 11 .

In EF Core 10 e versioni precedenti è stato possibile accedere alle proprietà non rilevate da EF Core tramite una proprietà speciale nello stato shadow denominata "__jObject" che contiene un JObject oggetto che rappresenta i dati ricevuti dall'archivio e dai dati che verranno archiviati:

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
}

Avviso

La "__jObject" proprietà faceva parte dell'infrastruttura di EF Core. Esiste solo in EF Core 10 e versioni precedenti ed è stato rimosso a partire da EF Core 11.

Uso di CosmosClient

Per separare completamente EF Core, ottenere l'oggetto CosmosClient che fa parte di Azure Cosmos DB SDK da DbContext:

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());
}

Valori delle proprietà mancanti

Nell'esempio precedente abbiamo rimosso la proprietà "TrackingNumber" dall'ordine. A causa del funzionamento dell'indicizzazione in Azure Cosmos DB, le query che fanno riferimento alla proprietà mancante altrove rispetto alla proiezione potrebbero restituire risultati imprevisti. Per esempio:

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}");
}

La query ordinata in realtà non restituisce risultati. Ciò significa che è necessario prestare attenzione a popolare sempre le proprietà mappate da EF Core quando si lavora direttamente con l'archivio dati.

Annotazioni

Questo comportamento potrebbe cambiare nelle versioni future di Azure Cosmos DB. Ad esempio, attualmente se i criteri di indicizzazione definiscono l'indice composito {Id/? ASC, NumeroDiTracciamento/? ASC)}, una query con 'ORDER BY c.Id ASC, c.Discriminator ASC' restituirebbe gli elementi che non hanno la "TrackingNumber" proprietà.