Migración de la aplicación para usar el SDK de .NET v3 de Azure Cosmos DB

SE APLICA A: NoSQL

Importante

Para obtener información sobre el SDK de .NET v3 de Azure Cosmos DB, consulte las notas de la versión, el repositorio de GitHub de .NET, las sugerencias de rendimiento del SDK de .NET v3 y la guía de solución de problemas.

En este artículo se destacan algunas de las cuestiones relacionadas con la actualización de la aplicación .NET existente al nuevo SDK de .NET v3 de Azure Cosmos DB para API para NoSQL. El SDK de .NET v3 de Azure Cosmos DB corresponde al espacio de nombres Microsoft.Azure.Azure Cosmos DB. Puede usar la información de este documento si va a migrar la aplicación desde cualquiera de los siguientes SDK de .NET de Azure Cosmos DB:

  • SDK de .NET Framework v2 de Azure Cosmos DB para la API para NoSQL
  • SDK de .NET Core v2 de Azure Cosmos DB para la API para NoSQL

Las instrucciones de este artículo también le ayudarán a migrar las siguientes bibliotecas externas que ahora forman parte del SDK de .NET v3 de Azure Cosmos DB para la API para NoSQL:

  • Biblioteca de procesadores de fuente de cambios para .NET 2.0
  • Biblioteca Bulk Executor para .NET 1.1 o superior

Novedades del SDK de .NET v3

El SDK v3 contiene muchas mejoras de facilidad de uso y rendimiento, entre las que se incluyen:

  • Nomenclatura intuitiva del modelo de programación
  • .NET Standard 2.0**
  • Mayor rendimiento gracias a la compatibilidad con API de transmisión
  • Jerarquía fluida que elimina la necesidad de una fábrica de URI
  • Compatibilidad integrada con la biblioteca de procesadores de fuente de cambios
  • Compatibilidad integrada para operaciones masivas
  • API de simulación para pruebas unitarias más sencillas
  • Compatibilidad con lotes transaccionales y Blazor
  • Serializadores conectables
  • Escalado de contenedores sin particiones y con escalabilidad automática

** El SDK tiene como destino .NET Standard 2.0, que unifica los SDK de .NET Framework y .NET Core existentes de Azure Cosmos DB en un solo SDK de .NET. Puede usar el SDK de .NET en cualquier plataforma que implemente .NET Standard 2.0, incluidas las aplicaciones .NET Framework 4.6.1 y versiones posteriores, y .NET Core 2.0 y versiones posteriores.

La mayoría de las funciones de red, la lógica de reintento y los niveles inferiores del SDK continúan en gran medida iguales.

El SDK de .NET v3 de Azure Cosmos DB es ahora de código abierto. Además de agradecer las solicitudes de incorporación de cambios, registraremos los problemas y realizaremos un seguimiento de los comentarios en GitHub. Asimismo, trabajaremos en la incorporación de características que mejoren la experiencia del cliente.

Por qué migrar al SDK de .NET v3

Además de las numerosas mejoras de facilidad de uso y rendimiento, las inversiones en nuevas características realizadas en el último SDK no se trasladarán a las versiones anteriores. El SDK v2 está actualmente en modo de mantenimiento. Para lograr la mejor experiencia de desarrollo, se recomienda empezar siempre con la versión compatible del SDK más reciente.

Principales cambios de nombre del SDK v2 al SDK v3

Se han aplicado los siguientes cambios de nombre en el SDK de .NET 3.0, para adaptarse a las convenciones de nomenclatura de la API para NoSQL:

  • DocumentClient ahora se llama CosmosClient
  • Collection ahora se llama Container
  • Document ahora se llama Item

Todos los objetos de recursos cambian de nombre con propiedades adicionales, lo que incluye el nombre del recurso para mayor claridad.

A continuación se muestran algunos de los principales cambios en el nombre de clase:

SDK de .NET v2 SDK de .NET v3
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

Clases reemplazadas en el SDK de .NET v3

Las siguientes clases se han reemplazado en el SDK 3.0:

  • Microsoft.Azure.Documents.UriFactory

La clase Microsoft.Azure.Documents.UriFactory se ha reemplazado por el diseño fluido.

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

  • Microsoft.Azure.Documents.Document

Dado que el SDK v3 de .NET permite a los usuarios configurar un motor de serialización personalizado, no hay ningún reemplazo directo para el tipo Document. Si se utiliza Newtonsoft.Json (motor de serialización predeterminado), JObject se puede usar para lograr la misma funcionalidad. Si usa un motor de serialización diferente, puede utilizar su tipo de documento JSON base (por ejemplo, JsonDocument para System.Text.Json). La recomendación es usar un tipo de C# que refleje el esquema de los elementos, en lugar de depender de tipos genéricos.

  • Microsoft.Azure.Documents.Resource

No hay ningún reemplazo directo para Resource; en los casos en los que se usó para los documentos, siga las instrucciones de Document.

  • Microsoft.Azure.Documents.AccessCondition

IfNoneMatch o IfMatch ahora están disponibles directamente en Microsoft.Azure.Cosmos.ItemRequestOptions.

Cambios en la generación del identificador de elemento

El identificador de elemento ya no se rellena automáticamente en el SDK de .NET v3. Por lo tanto, debe incluir específicamente un identificador generado. Consulte el ejemplo siguiente:

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

Cambio en el comportamiento predeterminado del modo de conexión

El SDK v3 tiene ahora como valor predeterminado los modos de conexión directa y TCP en comparación con el SDK v2 anterior, que tenía como valor predeterminado los modos de conexión de puerta de enlace y HTTPS. Este cambio ofrece un rendimiento y una escalabilidad mejorados.

Cambios en FeedOptions (QueryRequestOptions en el SDK v3.0)

El nombre de la clase FeedOptions del SDK v2 ha cambiado a QueryRequestOptions en el SDK v3 y, dentro de la clase, se han efectuado cambios en varias propiedades, ya sea en el nombre o en el valor predeterminado, en tanto que otras se han quitado por completo.

SDK de .NET v2 SDK de .NET v3
FeedOptions.MaxDegreeOfParallelism QueryRequestOptions.MaxConcurrency: el valor predeterminado y el comportamiento asociado siguen siendo los mismos, las operaciones que se ejecutan en el cliente durante la ejecución de consultas en paralelo se ejecutarán en serie sin paralelismo.
FeedOptions.PartitionKey QueryRequestOptions.PartitionKey: comportamiento mantenido.
FeedOptions.EnableCrossPartitionQuery Quitado. El comportamiento predeterminado en el SDK 3.0 es que las consultas entre particiones se ejecutarán sin necesidad de habilitar la propiedad de forma específica.
FeedOptions.PopulateQueryMetrics Quitado. Ahora está habilitado de forma predeterminada y forma parte de los diagnósticos.
FeedOptions.RequestContinuation Quitado. Ahora ha pasado a formar parte de los métodos de consulta.
FeedOptions.JsonSerializerSettings Quitado. Vea cómo personalizar la serialización para obtener información adicional.
FeedOptions.PartitionKeyRangeId Quitado. El mismo resultado se puede obtener mediante FeedRange como entrada para el método de consulta.
FeedOptions.DisableRUPerMinuteUsage Quitado.

Construcción de un cliente

El SDK de .NET v3 proporciona una clase CosmosClientBuilder fluida que elimina la necesidad de la fábrica de URI del SDK v2.

Este diseño crea las direcciones URL internamente y permite pasar un solo objeto Container en lugar de DocumentClient, DatabaseName y DocumentCollection.

En el ejemplo siguiente se crea una nueva clase CosmosClientBuilder con un valor ConsistencyLevel seguro y una lista de ubicaciones preferidas:

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

Excepciones

Donde el SDK v2 usaba DocumentClientException para señalar errores durante las operaciones, el SDK v3 usa CosmosException, que expone los elementos StatusCode y Diagnostics, así como otros datos relacionados con la respuesta. Toda la información se serializa cuando se usa 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();
}

Diagnóstico

Donde el SDK v2 tenía diagnósticos solo directos disponibles mediante la propiedad RequestDiagnosticsString, el SDK v3 usa el elemento Diagnostics disponible en todas las respuestas y excepciones, que son más abundantes y no están restringidas al modo directo. Incluyen no solo el tiempo empleado en el SDK para la operación, sino también las regiones con las que ha contactado la operación:

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

Se ha cambiado el nombre de algunas opciones de configuración ConnectionPolicy o se ha reemplazado por CosmosClientOptions:

SDK de .NET v2 SDK de .NET v3
EnableEndpointDiscovery LimitToEndpoint: ahora el valor se ha invertido, si EnableEndpointDiscovery estaba establecido en true, LimitToEndpoint debería estar establecido en false. Antes de usar esta configuración, debe comprender cómo afecta al cliente.
ConnectionProtocol Quitado. El protocolo está asociado al modo, ya sea puerta de enlace (HTTPS) o directo (TCP). El modo directo con el protocolo HTTPS ya no se admite en el SDK V3; por ello, se recomienda usar el protocolo TCP.
MediaRequestTimeout Quitado. Ya no se admiten datos adjuntos.
SetCurrentLocation Se puede usar CosmosClientOptions.ApplicationRegion para lograr el mismo efecto.
PreferredLocations Se puede usar CosmosClientOptions.ApplicationPreferredRegions para lograr el mismo efecto.
UserAgentSuffix Se puede usar CosmosClientBuilder.ApplicationName para lograr el mismo efecto.
UseMultipleWriteLocations Quitado. El SDK detecta automáticamente si la cuenta admite varios puntos de conexión de escritura.

Directiva de indexación

En la directiva de indexación, no es posible configurar estas propiedades. Cuando no se especifican, estas propiedades ahora siempre tendrán los siguientes valores:

Nombre de la propiedad Nuevo valor (no configurable)
Kind range
dataType String y Number

Consulte esta sección para obtener ejemplos de directivas de indexación a fin de incluir y excluir rutas de acceso. Debido a las mejoras en el motor de consultas, la configuración de estas propiedades, incluso si se usa una versión anterior del SDK, no tiene ningún impacto en el rendimiento.

Token de sesión

Donde el SDK v2 exponía el token de sesión de una respuesta como ResourceResponse.SessionToken para los casos en los que se requería capturar el token de sesión, dado que el token de sesión es un encabezado, el SDK v3 expone ese valor en la propiedad Headers.Session de cualquier respuesta.

Timestamp

En aquellos casos en los que el SDK v2 exponía la marca de tiempo de un documento mediante la propiedad Timestamp, dado que Document ya no está disponible, los usuarios pueden asignar la Timestamp_ts a una propiedad de su modelo.

OpenAsync

Para los casos de uso en los que se usaba OpenAsync() para preparar el cliente del SDK v2, se puede usar CreateAndInitializeAsync para OpenAsync() un cliente del SDK v3.

Uso de las API de procesador de fuente de cambios directamente desde el SDK v3

El SDK v3 tiene compatibilidad integrada con las API de procesador de fuente de cambios, lo que le permite usar el mismo SDK para compilar la aplicación y la implementación del procesador de fuente de cambios. Anteriormente, tenía que usar una biblioteca de procesadores de fuente de cambios independiente.

Para obtener más información, consulte cómo migrar de la biblioteca de procesadores de fuente de cambios al SDK de .NET v3 de Azure Cosmos DB.

Consultas de fuente de cambios

La ejecución de consultas de fuente de cambios en el SDK v3 se considera que usa el modelo de extracción de fuente de cambios. Siga esta tabla para migrar la configuración:

SDK de .NET v2 SDK de .NET v3
ChangeFeedOptions.PartitionKeyRangeId FeedRange - Para lograr paralelismo en la lectura, se puede usar la fuente de cambios FeedRanges. Ya no es un parámetro necesario, puede leer fácilmente la fuente de cambios de un contenedor entero.
ChangeFeedOptions.PartitionKey FeedRange.FromPartitionKey - Un FeedRange que representa la clave de partición deseada se puede usar para leer la fuente de cambios para ese valor de clave de partición.
ChangeFeedOptions.RequestContinuation ChangeFeedStartFrom.Continuation - El iterador de fuente de cambios se puede detener y reanudar en cualquier momento guardando la continuación y usándola al crear un nuevo iterador.
ChangeFeedOptions.StartTime ChangeFeedStartFrom.Time
ChangeFeedOptions.StartFromBeginning ChangeFeedStartFrom.Beginning
ChangeFeedOptions.MaxItemCount ChangeFeedRequestOptions.PageSizeHint - El iterador de fuente de cambios se puede detener y reanudar en cualquier momento guardando la continuación y usándola al crear un nuevo iterador.
IDocumentQuery.HasMoreResults response.StatusCode == HttpStatusCode.NotModified - La fuente de cambios es conceptualmente infinita, por lo que siempre podría haber más resultados. Cuando una respuesta contiene el código de estado HttpStatusCode.NotModified, significa que no hay cambios nuevos para leer. Puede usarse para detener y guardar la continuación o para suspender o esperar temporalmente y, a continuación, llamar a ReadNextAsync de nuevo para averiguar si hay cambios nuevos.
Control de divisiones Ya no es necesario que los usuarios controlen las excepciones divididas al leer la fuente de cambios, las divisiones se controlarán de forma transparente sin necesidad de interacción del usuario.

Uso de la biblioteca Bulk Executor directamente desde el SDK v3

El SDK v3 tiene compatibilidad integrada con la biblioteca Bulk Executor, lo que permite usar el mismo SDK para compilar la aplicación y realizar operaciones masivas. Anteriormente, era necesario usar una biblioteca Bulk Executor independiente.

Para obtener más información, consulte cómo migrar de la biblioteca Bulk Executor a la compatibilidad con la ejecución en bloque en el SDK de .NET v3 de Azure Cosmos DB.

Personalización de serialización

El SDK V2 de .NET permite establecer JsonSerializerSettings en RequestOptions en el nivel operativo que se usa para deserializar el documento de resultados:

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

El SDK v3 de .NET proporciona una interfaz de serializador para personalizar completamente el motor de serialización, u opciones de serialización más genéricas, como parte de la construcción del cliente.

La personalización de la serialización en el nivel operacional se puede lograr mediante el uso de las API de 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
        }
    }
}

Comparaciones de fragmentos de código

En el fragmento de código siguiente se muestran las diferencias en el modo en que se crean los recursos entre los SDK de .NET v2 y v3:

Operaciones de la base de datos

Crear una base de datos

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

Lectura de una base de datos por identificador

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

Eliminación de una base de datos

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

Operaciones de contenedor

Creación de un contenedor (escalabilidad automática + período de vida con expiración)

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

Lectura de las propiedades del contenedor

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

Eliminación de un contenedor

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

Operaciones con elementos y de consulta

Crear un elemento

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

Lectura de todos los elementos de un contenedor

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

Elementos de consulta

Cambios en SqlQuerySpec (QueryDefinition en el SDK v3.0)

La clase SqlQuerySpec de la versión 2 del SDK se ha renombrado a QueryDefinition en la versión 3 del SDK.

SqlParameterCollection y SqlParameter se han quitado. Ahora se agregan parámetros a QueryDefinition con un modelo de generador que usa QueryDefinition.WithParameter. Los usuarios pueden acceder a los parámetros con 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);
        }
    }
}

Eliminación de un elemento

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

Consulta de fuente de cambios

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

Pasos siguientes