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의 장점 중 하나는 저장 되는 데이터의 모양에 대 한 유연성입니다.However one of the strengths of Azure Cosmos DB is the flexibility in the shape of the data stored.

원시 JSON 액세스Accessing the raw JSON

shadow-state "__jObject" JObject 저장소에서 받은 데이터를 나타내는 및 저장 되는 데이터를 나타내는가 포함 된 이름이 인 섀도 상태의 특수 속성을 통해 EF Core에서 추적 되지 않는 속성에 액세스할 수 있습니다.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, 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.