EF Core Azure Cosmos DB プロバイダーでの非構造化データの操作Working with Unstructured Data in EF Core Azure Cosmos DB Provider

EF Core は、モデルで定義されたスキーマに従ったデータを簡単に操作できるように設計されています。EF Core was designed to make it easy to work with data that follows a schema defined in the model. ただし、Azure Cosmos DB の長所の1つは、格納されるデータの構造に柔軟性があることです。However one of the strengths of Azure Cosmos DB is the flexibility in the shape of the data stored.

生の JSON へのアクセスAccessing the raw JSON

EF Core によって追跡されない プロパティには"__jObject" JObject ストアから受信したデータと格納されるデータを表すを含む、という名前の特殊なプロパティを使用してアクセスできます。It is possible to access the properties that are not tracked by EF Core through a special property in shadow-state named "__jObject" that contains a JObject representing the data recieved from the store and data that will be stored:

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 インフラストラクチャの一部であるため、最後の手段としてのみ使用してください。将来のリリースで動作が異なる可能性があるためです。The "__jObject" property is part of the EF Core infrastructure and should only be used as a last resort as it is likely to have different behavior in future releases.

注意

エンティティに対する変更は、の間に格納されている値よりも優先され "__jObject" SaveChanges ます。Changes to the entity will override the values stored in "__jObject" during SaveChanges.

CosmosClient の使用Using CosmosClient

EF Core から完全に切り離すには、次のようにAZURE COSMOS DB SDK の一部であるCosmosClientオブジェクトを取得し DbContext ます。To decouple completely from EF Core get the CosmosClient object that is part of the Azure Cosmos DB SDK from 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());
}

プロパティ値がありませんMissing property values

前の例では、順序からプロパティを削除しました "TrackingNumber"In the previous example we removed the "TrackingNumber" property from the order. Cosmos DB でのインデックス作成がどのように機能するのかによって、プロジェクション以外の場所に存在しないプロパティを参照するクエリは、予期しない結果を返す可能性があります。Because of how indexing works in Cosmos DB, queries that reference the missing property somewhere else than in the projection could return unexpected results. 次に例を示します。For example:

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

並べ替えられたクエリは実際には結果を返しません。The sorted query actually returns no results. つまり、ストアを直接操作するときは、常に EF Core によってマップされたプロパティを設定する必要があります。This means that one should take care to always populate properties mapped by EF Core when working with the store directly.

注意

この動作は、Cosmos の将来のバージョンで変更される可能性があります。This behavior might change in future versions of Cosmos. たとえば、インデックス作成ポリシーで複合インデックス {Id/を定義している場合は、For instance, currently if the indexing policy defines the composite index {Id/? ASC、TrackingNumber/?ASC, TrackingNumber/? ASC)}、' ORDER BY c.Id ASC, c. 識別子 ASC ' を持つ クエリは、 プロパティが不足している項目を返し "TrackingNumber" ます。ASC)}, then a query that has 'ORDER BY c.Id ASC, c.Discriminator ASC' would return items that are missing the "TrackingNumber" property.