Migrieren einer Anwendung für die Verwendung des Azure Cosmos DB .NET SDK v3

GILT FÜR: NoSQL

Wichtig

Informationen zum Azure Cosmos DB .NET SDK v3 finden Sie in den Versionshinweisen, im .NET-GitHub-Repository, in den Tipps zur Leistungssteigerung für das .NET SDK v3 sowie im Handbuch zur Problembehandlung.

Dieser Artikel enthält Überlegungen zur Aktualisierung Ihrer vorhandenen .NET-Anwendung auf das neuere Azure Cosmos DB .NET SDK v3 für die API für NoSQL. Das Azure Cosmos DB .NET SDK v3 entspricht dem Microsoft.Azure.Azure Cosmos DB-Namespace. Sie können die Informationen in diesem Dokument verwenden, wenn Sie Ihre Anwendung von einem der folgenden Azure Cosmos DB .NET SDKs migrieren:

  • Azure Cosmos DB .NET Framework SDK v2 für die API für NoSQL
  • Azure Cosmos DB .NET Core SDK v2 für die API für NoSQL

Die Anweisungen in diesem Artikel helfen Ihnen auch beim Migrieren der folgenden externen Bibliotheken, die jetzt Teil des Azure Cosmos DB .NET SDK v3 für die API für NoSQL sind:

  • .NET-Änderungsfeed-Prozessorbibliothek 2.0
  • .NET Bulk Executor-Bibliothek 1.1 oder höher

Neuigkeiten im .NET v3 SDK

Das v3 SDK enthält viele Verbesserungen der Benutzerfreundlichkeit und Leistung, darunter:

  • Intuitive Benennung von Programmiermodellen
  • .NET-Standard 2.0 **
  • Leistungssteigerung durch Stream-API-Unterstützung
  • Fluent-Hierarchie, sodass keine URI-Factory mehr nötig ist
  • Integrierte Unterstützung für die Änderungsfeed-Prozessorbibliothek
  • Integrierte Unterstützung für Massenvorgänge
  • Pseudo-APIs für einfachere Unittests
  • Transaktionale Batch- und Blazor-Unterstützung
  • Austauschbare Serialisierungsmodule
  • Skalieren von nicht partitionierten Containern und Containern mit Autoskalierung

** Das SDK zielt auf .NET Standard 2.0 ab, welches das vorhandene Azure Cosmos DB .NET Framework und vorhandene .NET Core SDKs zu einem einzigen .NET SDK zusammenfasst. Sie können das .NET SDK auf jeder Plattform verwenden, die .NET Standard 2.0 implementiert, einschließlich Ihrer Anwendungen mit .NET Framework 4.6.1+ und .NET Core 2.0+.

Bei den meisten Netzwerken, der Retry-Logik und den unteren Ebenen des SDK gibt es größtenteils keine Änderungen.

Das Azure Cosmos DB .NET SDK v3 ist jetzt Open Source verfügbar. Wir freuen uns über alle Pull Requests und werden Probleme auf GitHub protokollieren und dort Feedback verfolgen. Wir arbeiten daran, sämtliche Funktionen zu integrieren, die die Kundenfreundlichkeit verbessern.

Gründe für das Migrieren auf das .NET v3 SDK

Neben den zahlreichen Verbesserungen der Benutzerfreundlichkeit und der Leistung werden beim neuesten SDK getätigte Investitionen in neue Funktionen nicht auf ältere Versionen zurückportiert. Das SDK v2 befindet sich derzeit im Wartungsmodus. Für eine optimale Entwicklungserfahrung wird empfohlen, stets mit der neuesten unterstützten Version des SDK zu beginnen.

Wichtige Namensänderungen vom v2 SDK zum v3 SDK

Im .NET 3.0 SDK wurden durchgängig die folgenden Namensänderungen angewandt, um es an die API-Benennungskonventionen für die API für NoSQL anzupassen:

  • DocumentClient wird umbenannt in CosmosClient.
  • Collection wird umbenannt in Container.
  • Document wird umbenannt in Item.

Alle Ressourcenobjekte werden mit zusätzlichen Eigenschaften umbenannt, die aus Gründen der Übersichtlichkeit den Ressourcennamen umfassen.

Dies sind einige der wichtigsten Änderungen von Klassennamen:

.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

Im .NET v3 SDK ersetzte Klassen

Die folgenden Klassen wurden im SDK Version 3.0 ersetzt:

  • Microsoft.Azure.Documents.UriFactory

Die Klasse Microsoft.Azure.Documents.UriFactory wurde durch das Fluent-Design ersetzt.

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

  • Microsoft.Azure.Documents.Document

Da das .NET v3 SDK Benutzern das Konfigurieren einer benutzerdefinierten Serialisierungs-Engine ermöglicht, gibt es keinen direkten Ersatz für den Typ Document. Bei Verwendung von Newtonsoft.Json (Standardserialisierungs-Engine) kann JObject verwendet werden, um die gleiche Funktionalität zu erreichen. Bei Verwendung einer anderen Serialisierungs-Engine können Sie den zugehörigen JSON-Basisdokumenttyp verwenden (z. B. JsonDocument für System.Text.Json). Es wird empfohlen, einen C#-Typ zu verwenden, der dem Schema Ihrer Elemente entspricht, anstatt sich auf generische Typen zu verlassen.

  • Microsoft.Azure.Documents.Resource

Es gibt keinen direkten Ersatz für Resource. Wenn sie für Dokumente verwendet wurde, befolgen Sie den Leitfaden für Document.

  • Microsoft.Azure.Documents.AccessCondition

IfNoneMatch oder IfMatch sind jetzt direkt auf Microsoft.Azure.Cosmos.ItemRequestOptions verfügbar.

Änderungen bei der Element-ID-Generierung

Die Element-ID wird im .NET v3 SDK nicht mehr automatisch aufgefüllt. Daher muss die Element-ID eine speziell generierte ID enthalten. Sehen Sie sich dazu das folgende Beispiel an:

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

Geändertes Standardverhalten für den Verbindungsmodus

Das SDK v3 verwendet jetzt standardmäßig die Verbindungsmodi „Direct“ und „TCP“, während für das vorherige SDK v2 standardmäßig die Verbindungsmodi „Gateway“ und „HTTPS“ festgelegt waren. Diese Änderung sorgt für eine verbesserte Leistung und Skalierbarkeit.

Änderungen an FeedOptions (QueryRequestOptions im v3.0 SDK)

Die FeedOptions-Klasse im SDK v2 wurde jetzt im SDK v3 in QueryRequestOptions umbenannt, und innerhalb der Klasse wurden mehrere Eigenschaften im Namen und/oder Standardwert geändert oder vollständig entfernt.

.NET v2 SDK .NET v3 SDK
FeedOptions.MaxDegreeOfParallelism QueryRequestOptions.MaxConcurrency: Der Standardwert und das zugehörige Verhalten bleiben unverändert. Vorgänge auf Clientseite werden während der parallelen Abfragenausführung seriell und ohne Parallelität ausgeführt.
FeedOptions.PartitionKey QueryRequestOptions.PartitionKey: Das Verhalten wurde beibehalten.
FeedOptions.EnableCrossPartitionQuery Entfernt. Als Standardverhalten werden im SDK 3.0 partitionsübergreifende Abfragen ausgeführt, ohne dass die Eigenschaft explizit aktiviert werden muss.
FeedOptions.PopulateQueryMetrics Entfernt. Jetzt standardmäßig aktiviert und Teil der Diagnose
FeedOptions.RequestContinuation Entfernt. Jetzt zu den Abfragemethoden hochgestuft
FeedOptions.JsonSerializerSettings Entfernt. Weitere Informationen finden Sie unter Anpassen der Serialisierung.
FeedOptions.PartitionKeyRangeId Entfernt. Dasselbe Ergebnis kann durch das Verwenden von FeedRange als Eingabe für die Abfragemethode erzielt werden.
FeedOptions.DisableRUPerMinuteUsage Entfernt.

Erstellen eines Clients

Das .NET SDK v3 bietet eine Fluent-CosmosClientBuilder-Klasse, weshalb keine SDK v2 URI-Factory mehr nötig ist.

Das Fluent-Design erstellt URLs intern und ermöglicht die Übergabe eines einzelnen Container-Objekts anstelle von einem/einer DocumentClient, DatabaseName und DocumentCollection.

Das folgende Beispiel erstellt einen neuen CosmosClientBuilder mit einem starken ConsistencyLevel und einer Liste bevorzugter Speicherorte:

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

Ausnahmen

Wo das v2 SDK DocumentClientException verwendete, um Fehler während Vorgängen zu signalisieren, verwendet das v3 SDK CosmosException, das StatusCode, Diagnostics und andere antwortbezogene Informationen verfügbar macht. Alle vollständigen Informationen werden serialisiert, wenn ToString() verwendet wird:

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

Diagnose

Wenn dem v2 SDK die „Direct-Only“-Diagnose über die Eigenschaft RequestDiagnosticsString zur Verfügung stand, verwendet das v3 SDK Diagnostics, das in allen Antworten und Ausnahmen zur Verfügung steht, die umfangreicher und nicht auf den direkten Modus eingeschränkt sind. Sie umfassen nicht nur die Zeit, die beim SDK für den Vorgang aufgewendet wurde, sondern auch die Regionen, die der Vorgang kontaktiert hat:

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

Einige Einstellungen in ConnectionPolicy wurden umbenannt oder durch CosmosClientOptions ersetzt:

.NET v2 SDK .NET v3 SDK
EnableEndpointDiscovery LimitToEndpoint – Der Wert wird jetzt invertiert; wenn EnableEndpointDiscovery auf true festgelegt wurde, sollte LimitToEndpoint auf false festgelegt werden. Bevor Sie diese Einstellung verwenden, müssen Sie verstehen, wie sie sich auf den Client auswirkt.
ConnectionProtocol Entfernt. Das Protokoll ist an den Modus gebunden – entweder „Gateway“ (HTTPS) oder „Direct“ (TCP). Der direkte Modus mit dem HTTPS-Protokoll wird von V3 SDK nicht mehr unterstützt. Die Empfehlung lautet, das TCP-Protokoll zu verwenden.
MediaRequestTimeout Entfernt. Anlagen werden nicht mehr unterstützt.
SetCurrentLocation Mit CosmosClientOptions.ApplicationRegion kann der gleiche Effekt erzielt werden.
PreferredLocations Mit CosmosClientOptions.ApplicationPreferredRegions kann der gleiche Effekt erzielt werden.
UserAgentSuffix Mit CosmosClientBuilder.ApplicationName kann der gleiche Effekt erzielt werden.
UseMultipleWriteLocations Entfernt. Das SDK erkennt automatisch, ob das Konto mehrere Schreibendpunkte unterstützt.

Indizierungsrichtlinie

In der Indizierungsrichtlinie können diese Eigenschaften nicht konfiguriert werden. Ohne Festlegung weisen diese Eigenschaften jetzt immer die folgenden Werte auf:

Eigenschaftenname Neuer Wert (nicht konfigurierbar)
Kind range
dataType String und Number

Exemplarische Indizierungsrichtlinien zum Ein- und Ausschließen von Pfaden finden Sie in diesem Abschnitt. Aufgrund von Verbesserungen in der Abfrage-Engine hat die Konfiguration dieser Eigenschaften auch bei Verwendung einer älteren SDK-Version keine Auswirkungen auf die Leistung.

Sitzungstoken

Wenn das v2 SDK das Sitzungstoken einer Antwort wie ResourceResponse.SessionToken für Fälle verfügbar gemacht hat, in denen die Erfassung des Tokens erforderlich war (weil es ein Header ist), macht das v3 SDK diesen Wert in der Eigenschaft Headers.Session jeder beliebigen Antwort verfügbar.

Timestamp

Wenn das v2 SDK den Zeitstempel eines Dokuments über die Timestamp-Eigenschaft verfügbar gemacht hat, weil Document nicht mehr zur Verfügung steht, können Benutzer*innen die _tsTimestamp einer Eigenschaft in ihrem Modell zuordnen.

OpenAsync

Für Anwendungsfälle, in denen OpenAsync() zum Aufwärmen des v2 SDK-Clients verwendet wurde, kann CreateAndInitializeAsync sowohl zum OpenAsync() eines v3 SDK-Clients verwendet werden.

Verwenden der Änderungsfeed-Prozessor-APIs direkt aus dem v3 SDK

Das v3 SDK verfügt über eine integrierte Unterstützung für die Änderungsfeed-Prozessor-APIs, sodass Sie dasselbe SDK zum Erstellen Ihrer Anwendung und für die Änderungsfeed-Prozessor-Implementierung verwenden können. Zuvor musste hierfür eine separate Änderungsfeed-Prozessorbibliothek verwendet werden.

Weitere Informationen hierzu finden Sie unter Migrieren von der Änderungsfeed-Prozessorbibliothek zum Azure Cosmos DB .NET v3 SDK.

Änderungsfeedabfragen

Die Ausführung von Änderungsfeedabfragen für das v3 SDK wird als Verwendung des Pullmodells für den Änderungsfeed betrachtet. Halten Sie sich an diese Tabelle, um die Konfiguration zu migrieren:

.NET v2 SDK .NET v3 SDK
ChangeFeedOptions.PartitionKeyRangeId FeedRange: Feedbereiche (FeedRanges) können verwendet werden, um paralleles Lesen des Änderungsfeeds zu ermöglichen. Dies ist kein erforderlicher Parameter mehr. Sie können nun ganz einfach den Änderungsfeed für einen gesamten Container lesen.
ChangeFeedOptions.PartitionKey FeedRange.FromPartitionKey: Ein Feedbereich (FeedRange), der den gewünschten Partitionsschlüssel darstellt, kann zum Lesen des Änderungsfeeds für diesen Partitionsschlüsselwert verwendet werden.
ChangeFeedOptions.RequestContinuation ChangeFeedStartFrom.Continuation: Der Änderungsfeediterator kann jederzeit beendet und fortgesetzt werden, indem Sie Fortsetzungstoken speichern und beim Erstellen eines neuen Iterators verwenden.
ChangeFeedOptions.StartTime ChangeFeedStartFrom.Time
ChangeFeedOptions.StartFromBeginning ChangeFeedStartFrom.Beginning
ChangeFeedOptions.MaxItemCount ChangeFeedRequestOptions.PageSizeHint: Der Änderungsfeediterator kann jederzeit beendet und fortgesetzt werden, indem Sie Fortsetzungstoken speichern und beim Erstellen eines neuen Iterators verwenden.
IDocumentQuery.HasMoreResults response.StatusCode == HttpStatusCode.NotModified: Der Änderungsfeed ist konzeptionell unendlich. Es ist also theoretisch immer möglich, dass noch weitere Ergebnisse vorhanden sind. Wenn eine Antwort den Statuscode HttpStatusCode.NotModified enthält, bedeutet dies, dass zu diesem Zeitpunkt keine neuen Änderungen zum Lesen vorhanden sind. Sie können damit den Vorgang beenden und das Fortsetzungstoken speichern oder den Vorgang vorübergehend in den Ruhezustand versetzen bzw. eine Weile warten und dann ReadNextAsync erneut aufrufen, um auf neue Änderungen zu testen.
Behandlung von Aufteilungen Es ist nicht mehr erforderlich, dass Benutzer Aufteilungsausnahmen beim Lesen des Änderungsfeeds behandeln. Aufteilungen werden transparent behandelt, ohne dass eine Benutzerinteraktion erforderlich ist.

Verwenden der Bulk Executor-Bibliothek direkt aus dem v3 SDK

Das v3 SDK verfügt über eine integrierte Unterstützung für die Bulk Executor-Bibliothek, sodass Sie dasselbe SDK zum Erstellen Ihrer Anwendung und für das Ausführen von Massenvorgängen verwenden können. Zuvor mussten Sie eine separate Bulk Executor-Bibliothek verwenden.

Weitere Informationen hierzu finden Sie unter Migrieren von der Bulk Executor-Bibliothek zur Unterstützung von Massenvorgängen im .NET SDK v3 von Azure Cosmos DB.

Anpassen der Serialisierung

Das .NET V2 SDK ermöglicht das Festlegen von JsonSerializerSettings in RequestOptions auf Betriebsebene, die zum Deserialisieren des Ergebnisdokuments verwendet wird:

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

Das .NET SDK v3 stellt eine Serialisierungsschnittstelle zum vollständigen Anpassen der Serialisierungs-Engine oder allgemeinere Serialisierungsoptionen im Rahmen der Clientkonstruktion bereit.

Das Anpassen der Serialisierung auf Betriebsebene kann durch die Verwendung von Stream-APIs erreicht werden:

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

Vergleich von Codeausschnitten

Im folgenden Codeausschnitt sehen Sie die Unterschiede bei der Ressourcenerstellung zwischen dem .NET v2 und dem .NET v3 SDK:

Datenbankvorgänge

Erstellen einer Datenbank

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

Lesen einer Datenbank nach 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()}");
        }
    }
}

Löschen einer Datenbank

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

Containervorgänge

Erstellen eines Containers (Autoskalierung + Gültigkeitsdauer mit Ablauf)

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

Lesen von Containereigenschaften

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

Löschen eines Containers

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

Element- und Abfragevorgänge

Erstellen eines Elements

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

Lesen aller Elemente in einem Container

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

Abfrageelemente

Änderungen an SqlQuerySpec (QueryDefinition in SDK v3.0)

Die SqlQuerySpec-Klasse in SDK v2 wurde jetzt in QueryDefinition im SDK v3 in umbenannt.

SqlParameterCollection und SqlParameter wurden entfernt. Parameter werden jetzt QueryDefinition mithilfe eines Generator-Modells unter Verwendung von QueryDefinition.WithParameter hinzugefügt. Benutzer können mit QueryDefinition.GetQueryParameters auf die Parameter zugreifen.

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

Löschen eines Elements

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

Änderungsfeedabfrage

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

Nächste Schritte