Миграция приложения для использование пакета SDK версии 3 .NET для Azure Cosmos DB

ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL

Внимание

Дополнительные сведения о пакете SDK версии 3 .NET для Azure Cosmos DB см. в заметках о выпуске, в Репозитории .NET GitHub, в советах по повышению эффективности для пакета SDK версии 3 для .NET, а также в руководстве по устранению неполадок.

В этой статье рассматриваются некоторые рекомендации по обновлению существующего приложения .NET до более нового пакета SDK для .NET Azure Cosmos DB версии 3 для API для NoSQL. Пакет SDK для .NET для Azure Cosmos DB версии 3 соответствует пространству имен Microsoft.Azure Cosmos DB. Сведения из этого документа можно использовать при переводе приложения с любого из следующих пакетов средств разработки .NET для Azure Cosmos DB:

  • Пакет SDK платформа .NET Framework Azure Cosmos DB версии 2 для API для NoSQL
  • Пакет SDK для .NET Core для Azure Cosmos DB версии 2 для API для NoSQL

Инструкции в этой статье также помогут перенести следующие внешние библиотеки, которые теперь являются частью пакета SDK для .NET для Azure Cosmos DB версии 3 для API для NoSQL:

  • Библиотека обработчика канала изменений .NET версии 2.0
  • Библиотека исполнителя массовых операций .NET версии 1.1 или более поздней

Новые возможности версии 3 пакета SDK для .NET

Пакет SDK версии 3 содержит множество улучшений для удобства использования и повышения эффективности, включая перечисленные ниже.

  • Понятная схема именования в модели программирования
  • .NET Standard 2.0**
  • Повышение производительности за счет поддержки потоков API
  • Иерархия Fluent, которая устраняет потребность в фабрике URI
  • Встроенная поддержка библиотеки обработчика канала изменений
  • Встроенная поддержка массовых операций
  • Специальные API, упрощающие модульное тестирование
  • Поддержка пакетов транзакций и Blazor
  • Подключаемые сериализаторы
  • Масштабирование контейнеров без секционирования и с автомасштабированием

** Пакет SDK предназначен для версии .NET Standard 2.0, в которой существующие SDK для платформы .NET для Azure Cosmos DB и .NET Core объединены в общий пакет SDK для .NET. Пакет SDK для .NET можно использовать на любой платформе, реализующей функции .NET Standard 2.0, включая приложения на базе .NET Framework 4.6.1+ и .NET Core 2.0+.

Большая часть логики сетевых соединений и повторных попыток, а также более низкие уровни SDK в основном остаются без изменений.

Пакет SDK версии 3 для .NET для Azure Cosmos DB теперь является продуктом с открытым исходным кодом. Мы приветствуем любые запросы на вытягивание и следим за опубликованными проблемами и отзывами на сайте GitHub. Мы будем стараться внедрить любые возможности, которые улучшат взаимодействие с клиентами.

Зачем переходить на пакет SDK версии 3для .NET

Помимо многочисленных улучшений с точки зрения удобства и эффективности, новые функции, добавленные в последнюю версию SDK, не будут переноситься в более старые версии. В настоящее время пакет SDK версии 2 находится в режиме обслуживания. Для максимального удобства рекомендуем всегда начинать разработку с последней поддерживаемой версии пакета SDK.

Важные изменения имен при переходе с версии 2 пакета SDK на версию 3

Следующие изменения имен были применены в пакете SDK для .NET 3.0 для соответствия соглашениям об именовании API для API для NoSQL:

  • DocumentClient переименовывается в CosmosClient
  • Collection переименовывается в Container
  • Document переименовывается в Item

Все объекты ресурсов переименовываются с использованием дополнительных свойств, которые для ясности содержат имя ресурса.

Ниже перечислены некоторые важные изменения в именах классов.

Пакет SDK версии 2 для .NET Пакет SDK версии 3 для .NET
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

Замена классов в пакете SDK версии 3 для .NET

В пакете SDK версии 3.0 были заменены перечисленные ниже классы.

  • Microsoft.Azure.Documents.UriFactory

Класс Microsoft.Azure.Docументс.UriFactory был заменен функциями Fluent Design.

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

  • Microsoft.Azure.Documents.Document

Так как пакет SDK для .NET версии 3 позволяет пользователям настраивать пользовательский механизм сериализации, то для типа нет прямой замены Document . При использовании Newtonsoft.Json (механизм сериализации по умолчанию) для выполнения этой функции можно использовать JObject. При использовании другого механизма сериализации можно использовать базовый тип документа JSON (например, JsonDocument для System.Text.Json). Рекомендуется использовать тип C#, который отражает схему элементов, а не полагаться на универсальные типы.

  • Microsoft.Azure.Documents.Resource

В случаях, когда она использовалась для документов, не существует прямой заменыResource, следуйте указаниям.Document

  • Microsoft.Azure.Documents.AccessCondition

IfNoneMatch или IfMatch теперь доступны напрямую Microsoft.Azure.Cosmos.ItemRequestOptions .

Изменения в создании идентификаторов элементов

В пакете SDK версии 3 для .NET идентификатор элемента больше не подставляется автоматически. Таким образом, идентификатор элемента должен содержать специально сгенерированное идентификационное значение. Вот пример:

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

Изменение поведения по умолчанию для режима соединения

Пакет SDK версии 3 теперь по умолчанию использует режимы подключения Direct+ TCP по сравнению с предыдущим пакетом SDK версии 2, который по умолчанию используется в режимах подключений Gateway + HTTPS. Это изменение помогает повысить производительность и масштабируемость.

Изменения параметров FeedOptions (QueryRequestOptions в пакете SDK версии 3.0)

Класс FeedOptions в пакете SDK версии 2 был переименован в QueryRequestOptions версии 3. В пределах этого класса у некоторых свойств было изменено имя и/или значение по умолчанию либо они были полностью удалены.

Пакет SDK версии 2 для .NET Пакет SDK версии 3 для .NET
FeedOptions.MaxDegreeOfParallelism QueryRequestOptions.MaxConcurrency — Значение по умолчанию и связанное поведение остается неизменным, операции запускаются на стороне клиента во время параллельного выполнения запроса, будут выполняться последовательно без параллелизма.
FeedOptions.PartitionKey QueryRequestOptions.PartitionKey — поведение поддерживается.
FeedOptions.EnableCrossPartitionQuery Удалено. Поведение по умолчанию в пакете SDK 3.0 заключается в том, что межсекционные запросы будут выполняться без необходимости включить свойство специально.
FeedOptions.PopulateQueryMetrics Удалено. Теперь она включена по умолчанию и частью диагностика.
FeedOptions.RequestContinuation Удалено. Теперь он повышен до методов запроса.
FeedOptions.JsonSerializerSettings Удалено. Узнайте, как настроить сериализацию для получения дополнительных сведений.
FeedOptions.PartitionKeyRangeId Удалено. Тот же результат можно получить с помощью FeedRange в качестве входных данных для метода запроса.
FeedOptions.DisableRUPerMinuteUsage Удалено.

Создание клиента

В пакете SDK версии 3 для .NET есть класс Fluent CosmosClientBuilder, который заменяет потребность в фабрике URI версии 2.

Fluent Design создает URL-адреса внутри и позволяет передавать один объект Container вместо DocumentClient, DatabaseName, и DocumentCollection.

В примере ниже создается новый объект CosmosClientBuilder со строгим уровнем ConsistencyLevel и списком предпочтительных расположений.

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

Исключения

Если пакет SDK версии 2 используется DocumentClientException для сигнализации об ошибках во время операций, то пакет SDK версии 3 использует CosmosException, который предоставляет StatusCode, Diagnostics и другую информацию, связанную с ответами. Вся полная информация сериализуется при использовании 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();
}

Диагностика

Если в пакете SDK версии 2 была доступна диагностика только прямого подключения с помощью свойства RequestDiagnosticsString, то пакет SDK версии 3 использует доступный 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

Пакет SDK версии 2 для .NET Пакет SDK версии 3 для .NET
EnableEndpointDiscovery LimitToEndpoint — значение теперь инвертировано, если для пункта EnableEndpointDiscovery задано значение true, то для LimitToEndpoint должно быть задано false. Перед использованием этого параметра необходимо понять, как он влияет на клиент.
ConnectionProtocol Удалено. Протокол связан с режимом — шлюзом (HTTPS) или Direct (TCP). Прямой режим с протоколом HTTPS в пакете SDK версии 3 больше не поддерживается, и мы рекомендуем перейти на протокол TCP.
MediaRequestTimeout Удалено. Вложения больше не поддерживаются.
SetCurrentLocation Для достижения того же результата можно использовать CosmosClientOptions.ApplicationRegion.
PreferredLocations Для достижения того же результата можно использовать CosmosClientOptions.ApplicationPreferredRegions.
UserAgentSuffix Для достижения того же результата можно использовать CosmosClientBuilder.ApplicationName.
UseMultipleWriteLocations Удалено. Пакет SDK автоматически определяет, поддерживает ли учетная запись несколько конечных точек записи.

Политика индексирования

В политике индексации невозможно настроить эти свойства. Если не указано иное, эти свойства теперь всегда будут иметь следующие значения:

Имя свойства Новое значение (не настраиваемое)
Kind range
dataType String и Number.

В этом разделе приведены примеры политики индексирования для включения и исключения путей. Благодаря улучшениям в обработчике запросов настройка этих свойств не влияет на производительность, даже если вы используете старую версию пакета SDK.

Токен сеанса

В случаях, когда пакет SDK версии 2 предоставляет токен сеанса ответа как ResourceResponse.SessionToken, когда требуется захват токена сеанса, и поскольку токен сеанса является заголовком, то пакет SDK версии 3 предоставляет это значение в свойстве Headers.Session любого ответа.

Метка времени

В тех случаях, когда пакет SDK версии 2 предоставляет метку времени документа через свойство Timestamp, поскольку Document больше не доступно, пользователи могут сопоставить _ts системное свойство со свойством в своей модели.

OpenAsync

Для вариантов использования, при которых OpenAsync() применялся для подготовки клиента пакета SDK версии 2, CreateAndInitializeAsync можно использовать для создания и подготовки клиента пакета SDK версии 3.

Использование API-интерфейсов обработчика канала изменений непосредственно из пакета SDK версии 3

В пакет SDK версии 3 добавлена встроенная поддержка API-интерфейсов обработчика канала изменений, благодаря чему один пакет SDK можно использовать для создания приложения и реализации обработчика. Ранее приходилось использовать отдельную библиотеку обработчика канала изменений.

Дополнительные сведения см. в статье о переходе с библиотеки обработчика канала изменений на пакет SDK версии 3 для .NET для Azure Cosmos DB.

Запросы канала изменений

Выполнение запросов канала изменений в пакете SDK версии 3 считается использованием модели извлечения канала изменений. Для переноса конфигурации следуйте этой таблице:

Пакет SDK версии 2 для .NET Пакет SDK версии 3 для .NET
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 для проверки новых изменений.
Обработка разделения Пользователям больше не требуется обрабатывать исключения разделения при чтении канала изменений, разделение будет прозрачно обрабатываться без необходимости взаимодействия с пользователем.

Использование библиотеки исполнителя массовых операций непосредственно из пакета SDK версии 3

В пакет SDK версии 3 добавлена встроенная поддержка библиотеки исполнителя массовых операций, благодаря чему один пакет SDK можно использовать для создания приложения и выполнения массовых операций. Ранее приходилось использовать отдельную библиотеку исполнителя массовых операций.

Подробнее см. статью Миграция из библиотеки исполнителя массовых операций на использование функции поддержки массовых операций в пакете SDK для Azure Cosmos DB .NET версии 3

Настраиваемая сериализация

Пакет SDK для .NET версии 2 позволяет задать JsonSerializerSettings в RequestOptions на рабочем уровне, используемом для десериализации документа результата:

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

Пакет SDK для .NET версии 3 предоставляет интерфейс сериализатора для полной настройки обработчика сериализации или более универсальных параметров сериализации в рамках построения клиента.

Настройка сериализации на уровне операции может быть достигнута с помощью API Stream:

// .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
        }
    }
}

Сравнение фрагментов кода

В следующем фрагменте кода показаны различия в создании ресурсов в версиях 2 и 3 пакета 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));

Чтение базы данных по идентификатору

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

Операции с контейнерами

Создание контейнера (автомасштабирование + время жизни с истечением срока действия)

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 (QueryDefinition в пакете SDK для версии 3.0)

Класс SqlQuerySpec в пакете SDK версии 2 переименован в QueryDefinition в пакете SDK версии 3.

Классы SqlParameterCollection и SqlParameter были удалены. Параметры в объект QueryDefinition теперь добавляются через построителя моделей с помощью функции QueryDefinition.WithParameter. Доступ к параметрам пользователи могут получить с помощью метода 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
        }
    }
}

Следующие шаги