Azure Cosmos DB .NET SDK v3를 사용하도록 애플리케이션 마이그레이션

적용 대상: NoSQL

Important

Azure Cosmos DB .NET SDK v3에 대해 알아보려면 릴리스 정보, .NET GitHub 리포지토리, .Net SDK v3 성능 팁문제 해결 가이드를 참조하세요.

이 문서에서는 기존 .NET 애플리케이션을 최신 API for NoSQL용 Azure Cosmos DB .NET SDK v3로 업그레이드하는 경우의 몇 가지 고려 사항을 중점적으로 설명합니다. Azure Cosmos DB .NET SDK v3는 Microsoft.Azure.Azure Cosmos DB 네임스페이스에 해당합니다. 다음 Azure Cosmos DB .NET SDK 중 하나에서 애플리케이션을 마이그레이션하는 경우 이 문서의 정보를 활용합니다.

  • API for NoSQL용 Azure Cosmos DB .NET Framework SDK v2
  • API for NoSQL용 Azure Cosmos DB .NET Core SDK v2

이 문서의 지침을 참조하면 API for NoSQL용 Azure Cosmos DB .NET SDK v3에 포함된 다음 외부 라이브러리도 마이그레이션할 수 있습니다.

  • .NET 변경 피드 프로세서 라이브러리 2.0
  • .NET 대량 실행기 라이브러리 1.1 이상

.NET v3 SDK의 새로운 기능

v3 SDK에는 다음과 같이 많은 유용성 및 성능 개선 사항이 포함되어 있습니다.

  • 직관적인 프로그래밍 모델 명명
  • .NET Standard 2.0 **
  • 스트림 API 지원을 통한 성능 향상
  • URI 팩터리의 필요성을 대체하는 흐름 계층 구조
  • 변경 피드 프로세서 라이브러리에 대한 기본 제공 지원
  • 대량 작업에 대한 기본 제공 지원
  • Mockable API를 통해 간단해진 유닛 네스트
  • 트랜잭션 일괄 처리 및 Blazor 지원
  • 플러그형 직렬 변환기
  • 분할되지 않은 자동 크기 조정 컨테이너의 크기 조정

** SDK는 기존 Azure Cosmos DB .NET Framework와 .NET Core SDK를 단일 .NET SDK로 통합하는 .NET Standard 2.0을 대상으로 합니다. .NET Framework 4.6.1+ 및 .NET Core 2.0+ 애플리케이션을 포함하여 .NET Standard 2.0을 구현하는 모든 플랫폼에서 .NET SDK를 사용할 수 있습니다.

대부분의 네트워킹, 재시도 논리 및 낮은 수준의 SDK는 거의 변경되지 않습니다.

Azure Cosmos DB .NET SDK v3는 현재 오픈 소스입니다. 모든 끌어오기 요청을 수용하고 GitHub에서 문제를 로깅하며 피드백을 추적할 것입니다. 사용자 환경을 개선할 수 있는 모든 기능을 활용하기 위해 노력하겠습니다.

.NET v3 SDK로 마이그레이션하는 이유

수많은 유용성 및 성능 개선 사항 외에도 최신 SDK에 투자된 새로운 기능을 접한다면 이전 버전을 다시 사용하지 않게 될 것입니다. v2 SDK는 현재 유지 관리 모드입니다. 최상의 개발 환경을 위해 항상 지원되는 최신 버전의 SDK로 시작하는 것이 좋습니다.

v2 SDK에서 v3 SDK로 주요 이름 변경

다음 이름 변경은 API for NoSQL의 API 명명 규칙에 맞추어 .NET 3.0 SDK 전반에 걸쳐 적용되었습니다.

  • DocumentClientCosmosClient로 이름이 바뀌었습니다.
  • CollectionContainer로 이름이 바뀌었습니다.
  • DocumentItem으로 이름이 바뀌었습니다.

모든 리소스 개체는 명확성을 위해 리소스 이름을 포함하는 추가 속성으로 이름이 변경됩니다.

다음은 몇 가지 주요 클래스 이름 변경 내용입니다.

.NET v2 SDK .NET v3 SDK
Microsoft.Azure.Documents.Client.DocumentClient Microsoft.Azure.Cosmos.CosmosClient
Microsoft.Azure.Documents.Client.ConnectionPolicy Microsoft.Azure.Cosmos.CosmosClientOptions
Microsoft.Azure.Documents.Client.DocumentClientException Microsoft.Azure.Cosmos.CosmosException
Microsoft.Azure.Documents.Client.Database Microsoft.Azure.Cosmos.DatabaseProperties
Microsoft.Azure.Documents.Client.DocumentCollection Microsoft.Azure.Cosmos.ContainerProperties
Microsoft.Azure.Documents.Client.RequestOptions Microsoft.Azure.Cosmos.ItemRequestOptions
Microsoft.Azure.Documents.Client.FeedOptions Microsoft.Azure.Cosmos.QueryRequestOptions
Microsoft.Azure.Documents.Client.StoredProcedure Microsoft.Azure.Cosmos.StoredProcedureProperties
Microsoft.Azure.Documents.Client.Trigger Microsoft.Azure.Cosmos.TriggerProperties
Microsoft.Azure.Documents.SqlQuerySpec Microsoft.Azure.Cosmos.QueryDefinition

.NET v3 SDK에서 바뀌는 클래스

다음 클래스는 3.0 SDK에서 바뀌었습니다.

  • Microsoft.Azure.Documents.UriFactory

Microsoft.Azure.Documents.UriFactory 클래스가 흐름 디자인으로 바뀌었습니다.

Container container = client.GetContainer(databaseName,containerName);
ItemResponse<SalesOrder> response = await this._container.CreateItemAsync(
        salesOrder,
        new PartitionKey(salesOrder.AccountNumber));

  • Microsoft.Azure.Documents.Document

.NET v3 SDK를 사용하면 사용자가 사용자 지정 serialization 엔진을 구성할 수 있으므로 Document 유형을 직접 대체할 수 없습니다. Newtonsoft.Json(기본 serialization 엔진)을 사용할 때 JObject를 사용하여 동일한 기능을 얻을 수 있습니다. 다른 serialization 엔진을 사용하는 경우 기본 json 문서 종류를 사용할 수 있습니다(예: System.Text.Json의 경우 JsonDocument). 제네릭 형식을 사용하는 대신 항목의 스키마를 반영하는 C# 형식을 사용하는 것이 좋습니다.

  • Microsoft.Azure.Documents.Resource

문서에 사용된 경우 Resource에 대한 직접적인 대체는 없습니다. Document에 대한 지침을 따르세요.

  • Microsoft.Azure.Documents.AccessCondition

IfNoneMatch 또는 IfMatch는 이제 Microsoft.Azure.Cosmos.ItemRequestOptions에서 직접 사용할 수 있습니다.

항목 ID 생성 변경

.NET v3 SDK에서는 항목 ID가 자동으로 채워지지 않습니다. 따라서 항목 ID에는 특별히 생성된 ID가 포함되어야 합니다. 다음 예제를 봅니다.

[JsonProperty(PropertyName = "id")]
public Guid Id { get; set; }

연결 모드에 대한 기본 동작이 변경됨

게이트웨이 + HTTPS 연결 모드로 기본 설정되었던 이전 v2 SDK와 달리 SDK v3는 직접 + TCP 연결 모드로 기본 설정됩니다. 이 변경을 통해 성능 및 확장성이 향상되었습니다.

FeedOptions에 대한 변경(v3.0 SDK의 QueryRequestOptions)

이제 SDK v2의 FeedOptions 클래스가 SDK v3 및 클래스 내에서 QueryRequestOptions로 이름이 변경되었습니다. 여러 속성은 완전히 제거되거나 이름 및/또는 기본값이 변경되었습니다.

.NET v2 SDK .NET v3 SDK
FeedOptions.MaxDegreeOfParallelism QueryRequestOptions.MaxConcurrency - 기본값 및 관련 동작은 동일하게 유지됩니다. 병렬 쿼리 실행 중에 클라이언트 측에서 실행되는 작업은 병렬 처리 없이 직렬로 실행됩니다.
FeedOptions.PartitionKey QueryRequestOptions.PartitionKey - 동작이 유지됩니다.
FeedOptions.EnableCrossPartitionQuery 제거됩니다. SDK 3.0의 기본 동작은 속성을 사용하도록 설정하지 않아도 파티션 간 쿼리가 실행됩니다.
FeedOptions.PopulateQueryMetrics 제거됩니다. 이제 기본적으로 사용하도록 설정되고 진단의 일부가 됩니다.
FeedOptions.RequestContinuation 제거됩니다. 이제 쿼리 메서드로 자체 승격되었습니다.
FeedOptions.JsonSerializerSettings 제거됩니다. 자세한 내용은 serialization을 사용자 지정하는 방법을 참조하세요.
FeedOptions.PartitionKeyRangeId 제거됩니다. FeedRange를 쿼리 메서드에 대한 입력으로 사용하여 동일한 결과를 얻을 수 있습니다.
FeedOptions.DisableRUPerMinuteUsage 제거됩니다.

클라이언트 생성

.NET SDK v3는 SDK v2 URI 팩터리의 필요성을 대체하는 흐름 CosmosClientBuilder 클래스를 제공합니다.

흐름 디자인은 URL을 내부적으로 빌드하고 DocumentClient, DatabaseNameDocumentCollection 대신 단일 Container 개체가 전달될 수 있도록 합니다.

다음 예제에서는 강력한 ConsistencyLevel 및 기본 위치 목록을 사용하여 새 CosmosClientBuilder를 만듭니다.

CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(
    accountEndpoint: "https://testcosmos.documents.azure.com:443/",
    authKeyOrResourceToken: "SuperSecretKey")
.WithConsistencyLevel(ConsistencyLevel.Strong)
.WithApplicationRegion(Regions.EastUS);
CosmosClient client = cosmosClientBuilder.Build();

예외

v2 SDK가 작업 중 오류를 알리기 위해 DocumentClientException을 사용했다면 v3 SDK는 StatusCode, Diagnostics 및 기타 응답 관련 정보를 노출하는 CosmosException을 사용합니다. 모든 완전한 정보는 ToString()이 사용될 때 직렬화됩니다.

catch (CosmosException ex)
{
    HttpStatusCode statusCode = ex.StatusCode;
    CosmosDiagnostics diagnostics = ex.Diagnostics;
    // store diagnostics optionally with diagnostics.ToString();
    // or log the entire error details with ex.ToString();
}

진단

v2 SDK에 RequestDiagnosticsString 속성을 통해 사용할 수 있는 직접 전용 진단이 있는 경우 v3 SDK는 더 풍부하고 직접 모드에 국한되지 않는 모든 응답 및 예외에서 사용할 수 있는 Diagnostics를 사용합니다. 여기에는 작업을 위해 SDK에 소요된 시간뿐만 아니라 작업이 연결된 지역도 포함됩니다.

try
{
    ItemResponse<MyItem> response = await container.ReadItemAsync<MyItem>(
                    partitionKey: new PartitionKey("MyPartitionKey"),
                    id: "MyId");
    
    TimeSpan elapsedTime = response.Diagnostics.GetElapsedTime();
    if (elapsedTime > somePreDefinedThreshold)
    {
        // log response.Diagnostics.ToString();
        IReadOnlyList<(string region, Uri uri)> regions = response.Diagnostics.GetContactedRegions();
    }
}
catch (CosmosException cosmosException) {
    string diagnostics = cosmosException.Diagnostics.ToString();
    
    TimeSpan elapsedTime = cosmosException.Diagnostics.GetElapsedTime();
    
    IReadOnlyList<(string region, Uri uri)> regions = cosmosException.Diagnostics.GetContactedRegions();
    
    // log cosmosException.ToString()
}

ConnectionPolicy

ConnectionPolicy의 일부 설정은 CosmosClientOptions에 의해 이름이 변경되거나 대체되었습니다.

.NET v2 SDK .NET v3 SDK
EnableEndpointRediscovery LimitToEndpoint - 이제 값이 반전됩니다. EnableEndpointRediscoverytrue로 설정되어 있으면 LimitToEndpointfalse로 설정되어야 합니다. 이 설정을 사용하기 전에 클라이언트에 미치는 영향을 이해해야 합니다.
ConnectionProtocol 제거됩니다. 프로토콜은 게이트웨이(HTTPS) 또는 직접(TCP) 모드에 연결됩니다. HTTPS 프로토콜을 사용하는 직접 모드는 V3 SDK에서 더 이상 지원되지 않으며 TCP 프로토콜을 사용하는 것이 좋습니다.
MediaRequestTimeout 제거됩니다. 첨부 파일은 더 이상 지원되지 않습니다.
SetCurrentLocation CosmosClientOptions.ApplicationRegion을 사용하여 동일한 효과를 얻을 수 있습니다.
PreferredLocations CosmosClientOptions.ApplicationPreferredRegions을 사용하여 동일한 효과를 얻을 수 있습니다.
UserAgentSuffix CosmosClientBuilder.ApplicationName을 사용하여 동일한 효과를 얻을 수 있습니다.
UseMultipleWriteLocations 제거됩니다. SDK는 계정이 여러 쓰기 엔드포인트를 지원하는지 자동으로 검색합니다.

인덱싱 정책

인덱싱 정책에서는 이러한 속성을 구성할 수 없습니다. 지정하지 않으면 이러한 속성은 항상 다음과 같은 값을 갖습니다.

속성 이름 새 값(구성할 수 없음)
Kind range
dataType StringNumber

경로를 포함하고 제외하는 인덱싱 정책의 예는 이 섹션을 참조하세요. 쿼리 엔진의 개선으로 인해 이전 SDK 버전을 사용하는 경우에도 이러한 속성을 구성하는 것이 성능에 영향을 주지 않습니다.

세션 토큰

v2 SDK가 세션 토큰 캡처가 필요할 때 응답의 세션 토큰을 ResourceResponse.SessionToken으로 노출한 경우 세션 토큰이 헤더이므로 v3 SDK는 응답의 Headers.Session 속성에 해당 값을 노출합니다.

타임스탬프

v2 SDK가 Timestamp 속성을 통해 문서의 타임스탬프를 노출한 경우 Document를 더 이상 사용할 수 없으므로 사용자는 _ts시스템 속성을 모델의 속성에 매핑할 수 있습니다.

OpenAsync

OpenAsync()를 사용하여 v2 SDK 클라이언트를 워밍업하는 사용 사례의 경우 CreateAndInitializeAsync를 사용하여 v3 SDK 클라이언트를 만들고 워밍업할 수 있습니다.

v3 SDK에서 직접 변경 피드 프로세서 API 사용

v3 SDK는 동일한 SDK를 사용하여 애플리케이션을 빌드하고 변경 피드 프로세서를 구현할 수 있도록 변경 피드 프로세서 API에 대한 기본 제공을 지원합니다. 이전에는 별도의 변경 피드 프로세서 라이브러리를 사용해야 했습니다.

자세한 내용은 변경 피드 프로세서 라이브러리에서 Azure Cosmos DB .NET v3 SDK로 마이그레이션하는 방법을 참조하세요.

변경 피드 쿼리

v3 SDK에서 변경 피드 쿼리 실행은 변경 피드 끌어오기 모델을 사용하는 것으로 간주됩니다. 다음 표에 따라 구성을 마이그레이션합니다.

.NET v2 SDK .NET v3 SDK
ChangeFeedOptions.PartitionKeyRangeId FeedRange - 병렬 처리를 달성하기 위해서는 변경 피드 FeedRanges 읽기를 사용할 수 있습니다. 더 이상 필수 매개 변수가 아니고, 이제는 전체 컨테이너에 대해 변경 피드 읽기를 쉽게 수행할 수 있습니다.
ChangeFeedOptions.PartitionKey FeedRange.FromPartitionKey - 원하는 파티션 키를 나타내는 FeedRange를 사용해서 해당 파티션 키 값에 대한 변경 피드 읽기를 수행할 수 있습니다.
ChangeFeedOptions.RequestContinuation ChangeFeedStartFrom.Continuation - 구성을 저장하고 새 반복기를 만들 때 이를 사용하여 언제든지 변경 피드 반복기를 중지하고 재개할 수 있습니다.
ChangeFeedOptions.StartTime ChangeFeedStartFrom.Time
ChangeFeedOptions.StartFromBeginning ChangeFeedStartFrom.Beginning
ChangeFeedOptions.MaxItemCount ChangeFeedRequestOptions.PageSizeHint - 구성을 저장하고 새 반복기를 만들 때 이를 사용하여 언제든지 변경 피드 반복기를 중지하고 재개할 수 있습니다.
IDocumentQuery.HasMoreResults response.StatusCode == HttpStatusCode.NotModified - 변경 피드는 개념적으로 무한하므로 항상 더 많은 결과가 있을 수 있습니다. 응답에 HttpStatusCode.NotModified 상태 코드가 포함된 경우에는 이번에 읽을 새 변경 사항이 없습니다. 이를 사용해서 구성을 중지 및 저장하거나 일시적으로 절전 모드로 전환 또는 대기한 다음, 다시 ReadNextAsync를 호출하여 새 변경 사항을 테스트할 수 있습니다.
분할 처리 변경 피드를 읽을 때는 더 이상 분할 예외를 사용자가 처리할 필요가 없습니다. 사용자 상호 작용 없이도 분할이 투명하게 처리됩니다.

v3 SDK에서 직접 대량 실행기 라이브러리 사용

v3 SDK는 동일한 SDK를 사용하여 애플리케이션을 빌드하고 대량 작업을 수행할 수 있도록 대량 실행기 라이브러리에 대한 기본 제공을 지원합니다. 이전에는 별도의 대량 실행기 라이브러리를 사용해야 했습니다.

자세한 내용은 대량 실행기 라이브러리에서 Azure Cosmos DB .NET V3 SDK의 대량 지원으로 마이그레이션하는 방법을 참조하세요.

serialization 사용자 지정

.NET V2 SDK를 사용하면 결과 문서를 역직렬화하는 데 사용되는 작업 수준에서 RequestOptions에서 JsonSerializerSettings를 설정할 수 있습니다.

// .NET V2 SDK
var result = await container.ReplaceDocumentAsync(document, new RequestOptions { JsonSerializerSettings = customSerializerSettings })

.NET SDK v3는 직렬화 엔진을 완전히 사용자 지정하는 직렬 변환기 인터페이스 또는 클라이언트 생성의 일부로 보다 일반적인 serialization 옵션을 제공합니다.

Stream API를 사용하여 작업 수준에서 serialization을 사용자 지정할 수 있습니다.

// .NET V3 SDK
using(Response response = await this.container.ReplaceItemStreamAsync(stream, "itemId", new PartitionKey("itemPartitionKey"))
{

    using(Stream stream = response.ContentStream)
    {
        using (StreamReader streamReader = new StreamReader(stream))
        {
            // Read the stream and do dynamic deserialization based on type with a custom Serializer
        }
    }
}

코드 조각 비교

다음 코드 조각은 .NET v2와 v3 SDK에서 리소스를 만드는 방법의 차이점을 보여 줍니다.

데이터베이스 작업

데이터베이스 만들기

// Create database with no shared provisioned throughput
DatabaseResponse databaseResponse = await client.CreateDatabaseIfNotExistsAsync(DatabaseName);
Database database = databaseResponse;
DatabaseProperties databaseProperties = databaseResponse;

// Create a database with a shared manual provisioned throughput
string databaseIdManual = new string(DatabaseName + "_SharedManualThroughput");
database = await client.CreateDatabaseIfNotExistsAsync(databaseIdManual, ThroughputProperties.CreateManualThroughput(400));

// Create a database with shared autoscale provisioned throughput
string databaseIdAutoscale = new string(DatabaseName + "_SharedAutoscaleThroughput");
database = await client.CreateDatabaseIfNotExistsAsync(databaseIdAutoscale, ThroughputProperties.CreateAutoscaleThroughput(4000));

ID로 데이터베이스 읽기

// Read a database
Console.WriteLine($"{Environment.NewLine} Read database resource: {DatabaseName}");
database = client.GetDatabase(DatabaseName);
Console.WriteLine($"{Environment.NewLine} database { database.Id.ToString()}");

// Read all databases
string findQueryText = "SELECT * FROM c";
using (FeedIterator<DatabaseProperties> feedIterator = client.GetDatabaseQueryIterator<DatabaseProperties>(findQueryText))
{
    while (feedIterator.HasMoreResults)
    {
        FeedResponse<DatabaseProperties> databaseResponses = await feedIterator.ReadNextAsync();
        foreach (DatabaseProperties _database in databaseResponses)
        {
            Console.WriteLine($"{ Environment.NewLine} database {_database.Id.ToString()}");
        }
    }
}

데이터베이스 삭제

// Delete a database
await client.GetDatabase(DatabaseName).DeleteAsync();
Console.WriteLine($"{ Environment.NewLine} database {DatabaseName} deleted.");

// Delete all databases in an account
string deleteQueryText = "SELECT * FROM c";
using (FeedIterator<DatabaseProperties> feedIterator = client.GetDatabaseQueryIterator<DatabaseProperties>(deleteQueryText))
{
    while (feedIterator.HasMoreResults)
    {
        FeedResponse<DatabaseProperties> databaseResponses = await feedIterator.ReadNextAsync();
        foreach (DatabaseProperties _database in databaseResponses)
        {
            await client.GetDatabase(_database.Id).DeleteAsync();
            Console.WriteLine($"{ Environment.NewLine} database {_database.Id} deleted");
        }
    }
}

컨테이너 작업

컨테이너 만들기(자동 크기 조정 + 만료 시간에 대한 TTL(Time to Live))

private static async Task CreateManualThroughputContainer(Database database)
{
    // Set throughput to the minimum value of 400 RU/s manually configured throughput
    string containerIdManual = ContainerName + "_Manual";
    ContainerResponse container = await database.CreateContainerIfNotExistsAsync(
        id: containerIdManual,
        partitionKeyPath: partitionKeyPath,
        throughput: 400);
}

// Create container with autoscale
private static async Task CreateAutoscaleThroughputContainer(Database database)
{
    string autoscaleContainerId = ContainerName + "_Autoscale";
    ContainerProperties containerProperties = new ContainerProperties(autoscaleContainerId, partitionKeyPath);

    Container container = await database.CreateContainerIfNotExistsAsync(
        containerProperties: containerProperties,
        throughputProperties: ThroughputProperties.CreateAutoscaleThroughput(autoscaleMaxThroughput: 4000);
}

// Create a container with TTL Expiration
private static async Task CreateContainerWithTtlExpiration(Database database)
{
    string containerIdManualwithTTL = ContainerName + "_ManualTTL";

    ContainerProperties properties = new ContainerProperties
        (id: containerIdManualwithTTL,
        partitionKeyPath: partitionKeyPath);

    properties.DefaultTimeToLive = (int)TimeSpan.FromDays(1).TotalSeconds; //expire in 1 day

    ContainerResponse containerResponse = await database.CreateContainerIfNotExistsAsync(containerProperties: properties);
    ContainerProperties returnedProperties = containerResponse;
}

컨테이너 속성 읽기

private static async Task ReadContainerProperties(Database database)
{
    string containerIdManual = ContainerName + "_Manual";
    Container container = database.GetContainer(containerIdManual);
    ContainerProperties containerProperties = await container.ReadContainerAsync();
}

컨테이너 삭제

private static async Task DeleteContainers(Database database)
{
    string containerIdManual = ContainerName + "_Manual";

    // Delete a container
    await database.GetContainer(containerIdManual).DeleteContainerAsync();

    // Delete all CosmosContainer resources for a database
    using (FeedIterator<ContainerProperties> feedIterator = database.GetContainerQueryIterator<ContainerProperties>())
    {
        while (feedIterator.HasMoreResults)
        {
            foreach (ContainerProperties _container in await feedIterator.ReadNextAsync())
            {
                await database.GetContainer(_container.Id).DeleteContainerAsync();
                Console.WriteLine($"{Environment.NewLine}  deleted container {_container.Id}");
            }
        }
    }
}

항목 및 쿼리 작업

항목 만들기

private static async Task CreateItemAsync(Container container)
{
    // Create a SalesOrder POCO object
    SalesOrder salesOrder1 = GetSalesOrderSample("Account1", "SalesOrder1");
    ItemResponse<SalesOrder> response = await container.CreateItemAsync(salesOrder1,
        new PartitionKey(salesOrder1.AccountNumber));
}

private static async Task RunBasicOperationsOnDynamicObjects(Container container)
{
    // Dynamic Object
    dynamic salesOrder = new
    {
        id = "SalesOrder5",
        AccountNumber = "Account1",
        PurchaseOrderNumber = "PO18009186470",
        OrderDate = DateTime.UtcNow,
        Total = 5.95,
    };
    Console.WriteLine("\nCreating item");
    ItemResponse<dynamic> response = await container.CreateItemAsync<dynamic>(
        salesOrder, new PartitionKey(salesOrder.AccountNumber));
    dynamic createdSalesOrder = response.Resource;
}

컨테이너의 모든 항목 읽기

private static async Task ReadAllItems(Container container)
{
    // Read all items in a container
    List<SalesOrder> allSalesForAccount1 = new List<SalesOrder>();

    using (FeedIterator<SalesOrder> resultSet = container.GetItemQueryIterator<SalesOrder>(
        queryDefinition: null,
        requestOptions: new QueryRequestOptions()
        {
            PartitionKey = new PartitionKey("Account1"),
            MaxItemCount = 5
        }))
    {
        while (resultSet.HasMoreResults)
        {
            FeedResponse<SalesOrder> response = await resultSet.ReadNextAsync();
            SalesOrder salesOrder = response.First();
            Console.WriteLine($"\n1.3.1 Account Number: {salesOrder.AccountNumber}; Id: {salesOrder.Id}");
            allSalesForAccount1.AddRange(response);
        }
    }
}

쿼리 항목

SqlQuerySpec 변경 내용(v3.0 SDK의 QueryDefinition)

SDK v2의 SqlQuerySpec 클래스는 이제 SDK v3에서 QueryDefinition으로 이름이 변경되었습니다.

SqlParameterCollectionSqlParameter가 제거되었습니다. 이제 매개 변수가 QueryDefinition.WithParameter를 사용하는 빌더 모델과 함께 QueryDefinition에 추가됩니다. 사용자는 QueryDefinition.GetQueryParameters를 사용하여 매개 변수에 액세스할 수 있습니다.

private static async Task QueryItems(Container container)
{
    // Query for items by a property other than Id
    QueryDefinition queryDefinition = new QueryDefinition(
        "select * from sales s where s.AccountNumber = @AccountInput")
        .WithParameter("@AccountInput", "Account1");

    List<SalesOrder> allSalesForAccount1 = new List<SalesOrder>();
    using (FeedIterator<SalesOrder> resultSet = container.GetItemQueryIterator<SalesOrder>(
        queryDefinition,
        requestOptions: new QueryRequestOptions()
        {
            PartitionKey = new PartitionKey("Account1"),
            MaxItemCount = 1
        }))
    {
        while (resultSet.HasMoreResults)
        {
            FeedResponse<SalesOrder> response = await resultSet.ReadNextAsync();
            SalesOrder sale = response.First();
            Console.WriteLine($"\n Account Number: {sale.AccountNumber}; Id: {sale.Id};");
            allSalesForAccount1.AddRange(response);
        }
    }
}

항목 삭제

private static async Task DeleteItemAsync(Container container)
{
    ItemResponse<SalesOrder> response = await container.DeleteItemAsync<SalesOrder>(
        partitionKey: new PartitionKey("Account1"), id: "SalesOrder3");
}

변경 피드 쿼리

private static async Task QueryChangeFeedAsync(Container container)
{
    FeedIterator<SalesOrder> iterator = container.GetChangeFeedIterator<SalesOrder>(ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental);

    string continuation = null;
    while (iterator.HasMoreResults)
    {
        FeedResponse<SalesOrder> response = await iteratorForTheEntireContainer.ReadNextAsync();
    
        if (response.StatusCode == HttpStatusCode.NotModified)
        {
            // No new changes
            continuation = response.ContinuationToken;
            break;
        }
        else 
        {
            // Process the documents in response
        }
    }
}

다음 단계