QLDBAmazon-Treiber für. NET— Referenz zum Kochbuch - Amazon Quantum Ledger-Datenbank (AmazonQLDB)

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

QLDBAmazon-Treiber für. NET— Referenz zum Kochbuch

Wichtig

Hinweis zum Ende des Supports: Bestandskunden können Amazon QLDB bis zum Ende des Supports am 31.07.2025 nutzen. Weitere Informationen finden Sie unter Migrieren eines Amazon QLDB Ledgers zu Amazon Aurora SQL Postgre.

Dieses Referenzhandbuch zeigt allgemeine Anwendungsfälle des QLDB Amazon-Treibers für. NET. Es enthält C#-Codebeispiele, die zeigen, wie der Treiber verwendet wird, um grundlegende Erstellungs-, Lese-, Aktualisierungs- und Löschvorgänge (CRUD) auszuführen. Es enthält auch Codebeispiele für die Verarbeitung von Amazon Ion-Daten. Darüber hinaus werden in diesem Leitfaden bewährte Verfahren zur idempotenten Gestaltung von Transaktionen und zur Implementierung von Eindeutigkeitsbeschränkungen beschrieben.

Anmerkung

Dieses Thema enthält Codebeispiele für die standardmäßige Verarbeitung von Amazon Ion-Daten mithilfe des Ion-Objektmappers. QLDBführte den Ion-Objektmapper in Version 1.3.0 von ein. NETTreiber. Gegebenenfalls enthält dieses Thema auch Codebeispiele, bei denen die Standard-Ion-Bibliothek als Alternative verwendet wird. Weitere Informationen hierzu finden Sie unter Arbeiten mit Amazon Ion.

Der Treiber wird importiert

Das folgende Codebeispiel importiert den Treiber.

using Amazon.QLDB.Driver; using Amazon.QLDB.Driver.Generic; using Amazon.QLDB.Driver.Serialization;
using Amazon.QLDB.Driver; using Amazon.IonDotnet.Builders;

Der Treiber wird instanziiert

Im folgenden Codebeispiel wird eine Instanz des Treibers erstellt, die mithilfe der Standardeinstellungen eine Verbindung zu einem angegebenen Ledger-Namen herstellt.

Async
IAsyncQldbDriver driver = AsyncQldbDriver.Builder() .WithLedger("vehicle-registration") // Add Serialization library .WithSerializer(new ObjectSerializer()) .Build();
Sync
IQldbDriver driver = QldbDriver.Builder() .WithLedger("vehicle-registration") // Add Serialization library .WithSerializer(new ObjectSerializer()) .Build();
Async
IAsyncQldbDriver driver = AsyncQldbDriver.Builder().WithLedger("vehicle-registration").Build();
Sync
IQldbDriver driver = QldbDriver.Builder().WithLedger("vehicle-registration").Build();

CRUDOperationen

QLDBführt die Operationen create, read, update und delete (CRUD) als Teil einer Transaktion aus.

Warnung

Als bewährte Methode sollten Sie Ihre Schreibtransaktionen strikt idempotent gestalten.

Transaktionen idempotent machen

Wir empfehlen, Schreibtransaktionen idempotent zu machen, um unerwartete Nebenwirkungen bei Wiederholungsversuchen zu vermeiden. Eine Transaktion ist idempotent, wenn sie mehrfach ausgeführt werden kann und jedes Mal identische Ergebnisse liefert.

Stellen Sie sich zum Beispiel eine Transaktion vor, die ein Dokument in eine Tabelle mit dem Namen einfügt. Person Bei der Transaktion sollte zunächst geprüft werden, ob das Dokument bereits in der Tabelle vorhanden ist. Ohne diese Prüfung könnte die Tabelle am Ende doppelte Dokumente enthalten.

Nehmen wir an, die Transaktion wird serverseitig QLDB erfolgreich festgeschrieben, aber der Client läuft ab, während er auf eine Antwort wartet. Wenn die Transaktion nicht idempotent ist, könnte dasselbe Dokument bei einem erneuten Versuch mehrmals eingefügt werden.

Verwendung von Indizes zur Vermeidung vollständiger Tabellenscans

Es wird außerdem empfohlen, Anweisungen mit einer WHERE Prädikatklausel unter Verwendung eines Gleichheitsoperators für ein indiziertes Feld oder eine Dokument-ID auszuführen, z. B. oder. WHERE indexedField = 123 WHERE indexedField IN (456, 789) Ohne diese indizierte Suche QLDB muss ein Tabellenscan durchgeführt werden, was zu Transaktions-Timeouts oder Konflikten mit optimistischer Parallelitätssteuerung () führen kann. OCC

Mehr über OCC erfahren Sie unter QLDBAmazon-Parallelitätsmodell.

Implizit erstellte Transaktionen

Der Amazon. QLDBDer Fahrer. IQldbDriverDie Methode .Execute akzeptiert eine Lambda-Funktion, die eine Instanz von Amazon empfängt. QLDB.Treiber. TransactionExecutor, mit dem Sie Anweisungen ausführen können. Die Instanz von TransactionExecutor umschließt eine implizit erstellte Transaktion.

Sie können Anweisungen innerhalb der Lambda-Funktion ausführen, indem Sie die Execute Methode des Transaktions-Executors verwenden. Der Treiber schreibt die Transaktion implizit fest, wenn die Lambda-Funktion zurückkehrt.

In den folgenden Abschnitten wird gezeigt, wie grundlegende CRUD Operationen ausgeführt, eine benutzerdefinierte Wiederholungslogik angegeben und Eindeutigkeitsbeschränkungen implementiert werden.

Erstellen von Tabellen

Async
IAsyncResult<Table> createResult = await driver.Execute(async txn => { IQuery<Table> query = txn.Query<Table>("CREATE TABLE Person"); return await txn.Execute(query); }); await foreach (var result in createResult) { Console.WriteLine("{ tableId: " + result.TableId + " }"); // The statement returns the created table ID: // { tableId: 4o5Uk09OcjC6PpJpLahceE } }
Sync
IResult<Table> createResult = driver.Execute( txn => { IQuery<Table> query = txn.Query<Table>("CREATE TABLE Person"); return txn.Execute(query); }); foreach (var result in createResult) { Console.WriteLine("{ tableId: " + result.TableId + " }"); // The statement returns the created table ID: // { tableId: 4o5Uk09OcjC6PpJpLahceE } }
Async
// The result from driver.Execute() is buffered into memory because once the // transaction is committed, streaming the result is no longer possible. IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("CREATE TABLE Person"); }); await foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the created table ID: // { // tableId: "4o5Uk09OcjC6PpJpLahceE" // } }
Sync
// The result from driver.Execute() is buffered into memory because once the // transaction is committed, streaming the result is no longer possible. IResult result = driver.Execute(txn => { return txn.Execute("CREATE TABLE Person"); }); foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the created table ID: // { // tableId: "4o5Uk09OcjC6PpJpLahceE" // } }

Erstellen von Indizes

Async
IAsyncResult<Table> createResult = await driver.Execute(async txn => { IQuery<Table> query = txn.Query<Table>("CREATE INDEX ON Person(firstName)"); return await txn.Execute(query); }); await foreach (var result in createResult) { Console.WriteLine("{ tableId: " + result.TableId + " }"); // The statement returns the updated table ID: // { tableId: 4o5Uk09OcjC6PpJpLahceE } }
Sync
IResult<Table> createResult = driver.Execute(txn => { IQuery<Table> query = txn.Query<Table>("CREATE INDEX ON Person(firstName)"); return txn.Execute(query); }); foreach (var result in createResult) { Console.WriteLine("{ tableId: " + result.TableId + " }"); // The statement returns the updated table ID: // { tableId: 4o5Uk09OcjC6PpJpLahceE } }
Async
IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("CREATE INDEX ON Person(GovId)"); }); await foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the updated table ID: // { // tableId: "4o5Uk09OcjC6PpJpLahceE" // } }
Sync
IResult result = driver.Execute(txn => { return txn.Execute("CREATE INDEX ON Person(GovId)"); }); foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the updated table ID: // { // tableId: "4o5Uk09OcjC6PpJpLahceE" // } }

Dokumente lesen

// Assumes that Person table has documents as follows: // { "GovId": "TOYENC486FH", "FirstName" : "Brent" } // Person class is defined as follows: // public class Person // { // public string GovId { get; set; } // public string FirstName { get; set; } // } IAsyncResult<Person> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'")); }); await foreach (Person person in result) { Console.WriteLine(person.GovId); // Prints TOYENC486FH. Console.WriteLine(person.FirstName); // Prints Brent. }
Anmerkung

Wenn Sie eine Abfrage ohne indizierte Suche ausführen, wird ein vollständiger Tabellenscan aufgerufen. In diesem Beispiel empfehlen wir, einen Index für das GovId Feld zu verwenden, um die Leistung zu optimieren. Ohne aktivierten GovId Index können Abfragen eine höhere Latenz haben und auch zu OCC Konfliktausnahmen oder Transaktions-Timeouts führen.

Verwenden von Abfrageparametern

Im folgenden Codebeispiel wird ein Abfrageparameter vom Typ C# verwendet.

IAsyncResult<Person> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE FirstName = ?", "Brent")); }); await foreach (Person person in result) { Console.WriteLine(person.GovId); // Prints TOYENC486FH. Console.WriteLine(person.FirstName); // Prints Brent. }

Das folgende Codebeispiel verwendet mehrere Abfrageparameter vom Typ C#.

IAsyncResult<Person> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", "TOYENC486FH", "Brent")); }); await foreach (Person person in result) { Console.WriteLine(person.GovId); // Prints TOYENC486FH. Console.WriteLine(person.FirstName); // Prints Brent. }

Das folgende Codebeispiel verwendet ein Array von Abfrageparametern vom Typ C#.

// Assumes that Person table has documents as follows: // { "GovId": "TOYENC486FH", "FirstName" : "Brent" } // { "GovId": "ROEE1C1AABH", "FirstName" : "Jim" } // { "GovId": "YH844DA7LDB", "FirstName" : "Mary" } string[] ids = { "TOYENC486FH", "ROEE1C1AABH", "YH844DA7LDB" }; IAsyncResult<Person> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE GovId IN (?,?,?)", ids)); }); await foreach (Person person in result) { Console.WriteLine(person.FirstName); // Prints Brent on first iteration. // Prints Jim on second iteration. // Prints Mary on third iteration. }

Im folgenden Codebeispiel wird eine C#-Liste als Wert verwendet.

// Assumes that Person table has document as follows: // { "GovId": "TOYENC486FH", // "FirstName" : "Brent", // "Vehicles": [ // { "Make": "Volkswagen", // "Model": "Golf"}, // { "Make": "Honda", // "Model": "Civic"} // ] // } // Person class is defined as follows: // public class Person // { // public string GovId { get; set; } // public string FirstName { get; set; } // public List<Vehicle> Vehicles { get; set; } // } // Vehicle class is defined as follows: // public class Vehicle // { // public string Make { get; set; } // public string Model { get; set; } // } List<Vehicle> vehicles = new List<Vehicle> { new Vehicle { Make = "Volkswagen", Model = "Golf" }, new Vehicle { Make = "Honda", Model = "Civic" } }; IAsyncResult<Person> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE Vehicles = ?", vehicles)); }); await foreach (Person person in result) { Console.WriteLine("{"); Console.WriteLine($" GovId: {person.GovId},"); Console.WriteLine($" FirstName: {person.FirstName},"); Console.WriteLine(" Vehicles: ["); foreach (Vehicle vehicle in person.Vehicles) { Console.WriteLine(" {"); Console.WriteLine($" Make: {vehicle.Make},"); Console.WriteLine($" Model: {vehicle.Model},"); Console.WriteLine(" },"); } Console.WriteLine(" ]"); Console.WriteLine("}"); // Prints: // { // GovId: TOYENC486FH, // FirstName: Brent, // Vehicles: [ // { // Make: Volkswagen, // Model: Golf // }, // { // Make: Honda, // Model: Civic // }, // ] // } }
Async
// Assumes that Person table has documents as follows: // { "GovId": "TOYENC486FH", "FirstName" : "Brent" } IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'"); }); await foreach (IIonValue row in result) { Console.WriteLine(row.GetField("GovId").StringValue); // Prints TOYENC486FH. Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent. }
Sync
// Assumes that Person table has documents as follows: // { "GovId": "TOYENC486FH", "FirstName" : "Brent" } IResult result = driver.Execute(txn => { return txn.Execute("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'"); }); foreach (IIonValue row in result) { Console.WriteLine(row.GetField("GovId").StringValue); // Prints TOYENC486FH. Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent. }
Anmerkung

Wenn Sie eine Abfrage ohne indizierte Suche ausführen, wird ein vollständiger Tabellenscan aufgerufen. In diesem Beispiel empfehlen wir, einen Index für das GovId Feld zu verwenden, um die Leistung zu optimieren. Ohne aktivierten GovId Index können Abfragen eine höhere Latenz haben und auch zu OCC Konfliktausnahmen oder Transaktions-Timeouts führen.

Im folgenden Codebeispiel wird ein Abfrageparameter vom Typ Ion verwendet.

Async
IValueFactory valueFactory = new ValueFactory(); IIonValue ionFirstName = valueFactory.NewString("Brent"); IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("SELECT * FROM Person WHERE FirstName = ?", ionFirstName); }); await foreach (IIonValue row in result) { Console.WriteLine(row.GetField("GovId").StringValue); // Prints TOYENC486FH. Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent. }
Sync
IValueFactory valueFactory = new ValueFactory(); IIonValue ionFirstName = valueFactory.NewString("Brent"); IResult result = driver.Execute(txn => { return txn.Execute("SELECT * FROM Person WHERE FirstName = ?", ionFirstName); }); foreach (IIonValue row in result) { Console.WriteLine(row.GetField("GovId").StringValue); // Prints TOYENC486FH. Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent. }

Das folgende Codebeispiel verwendet mehrere Abfrageparameter.

Async
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionFirstName = valueFactory.NewString("Brent"); IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", ionGovId, ionFirstName); }); await foreach (IIonValue row in result) { Console.WriteLine(row.GetField("GovId").StringValue); // Prints TOYENC486FH. Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent. }
Sync
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionFirstName = valueFactory.NewString("Brent"); IResult result = driver.Execute(txn => { return txn.Execute("SELECT * FROM Person WHERE GovId = ? AND FirstName = ?", ionGovId, ionFirstName); }); foreach (IIonValue row in result) { Console.WriteLine(row.GetField("GovId").StringValue); // Prints TOYENC486FH. Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent. }

Das folgende Codebeispiel verwendet eine Liste von Abfrageparametern.

Async
// Assumes that Person table has documents as follows: // { "GovId": "TOYENC486FH", "FirstName" : "Brent" } // { "GovId": "ROEE1C1AABH", "FirstName" : "Jim" } // { "GovId": "YH844DA7LDB", "FirstName" : "Mary" } IIonValue[] ionIds = { valueFactory.NewString("TOYENC486FH"), valueFactory.NewString("ROEE1C1AABH"), valueFactory.NewString("YH844DA7LDB") }; IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("SELECT * FROM Person WHERE GovId IN (?,?,?)", ionIds); }); await foreach (IIonValue row in result) { Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent on first iteration. // Prints Jim on second iteration. // Prints Mary on third iteration. }
Sync
// Assumes that Person table has documents as follows: // { "GovId": "TOYENC486FH", "FirstName" : "Brent" } // { "GovId": "ROEE1C1AABH", "FirstName" : "Jim" } // { "GovId": "YH844DA7LDB", "FirstName" : "Mary" } IIonValue[] ionIds = { valueFactory.NewString("TOYENC486FH"), valueFactory.NewString("ROEE1C1AABH"), valueFactory.NewString("YH844DA7LDB") }; IResult result = driver.Execute(txn => { return txn.Execute("SELECT * FROM Person WHERE GovId IN (?,?,?)", ionIds); }); foreach (IIonValue row in result) { Console.WriteLine(row.GetField("FirstName").StringValue); // Prints Brent on first iteration. // Prints Jim on second iteration. // Prints Mary on third iteration. }

Im folgenden Codebeispiel wird eine Ionen-Liste als Wert verwendet. Weitere Informationen zur Verwendung verschiedener Ionentypen finden Sie unterArbeiten mit Amazon Ion-Datentypen in Amazon QLDB.

Async
// Assumes that Person table has document as follows: // { "GovId": "TOYENC486FH", // "FirstName" : "Brent", // "Vehicles": [ // { "Make": "Volkswagen", // "Model": "Golf"}, // { "Make": "Honda", // "Model": "Civic"} // ] // } IIonValue ionVehicle1 = valueFactory.NewEmptyStruct(); ionVehicle1.SetField("Make", valueFactory.NewString("Volkswagen")); ionVehicle1.SetField("Model", valueFactory.NewString("Golf")); IIonValue ionVehicle2 = valueFactory.NewEmptyStruct(); ionVehicle2.SetField("Make", valueFactory.NewString("Honda")); ionVehicle2.SetField("Model", valueFactory.NewString("Civic")); IIonValue ionVehicles = valueFactory.NewEmptyList(); ionVehicles.Add(ionVehicle1); ionVehicles.Add(ionVehicle2); IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("SELECT * FROM Person WHERE Vehicles = ?", ionVehicles); }); await foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // Prints: // { // GovId: "TOYENC486FN", // FirstName: "Brent", // Vehicles: [ // { // Make: "Volkswagen", // Model: "Golf" // }, // { // Make: "Honda", // Model: "Civic" // } // ] // } }
Sync
// Assumes that Person table has document as follows: // { "GovId": "TOYENC486FH", // "FirstName" : "Brent", // "Vehicles": [ // { "Make": "Volkswagen", // "Model": "Golf"}, // { "Make": "Honda", // "Model": "Civic"} // ] // } IIonValue ionVehicle1 = valueFactory.NewEmptyStruct(); ionVehicle1.SetField("Make", valueFactory.NewString("Volkswagen")); ionVehicle1.SetField("Model", valueFactory.NewString("Golf")); IIonValue ionVehicle2 = valueFactory.NewEmptyStruct(); ionVehicle2.SetField("Make", valueFactory.NewString("Honda")); ionVehicle2.SetField("Model", valueFactory.NewString("Civic")); IIonValue ionVehicles = valueFactory.NewEmptyList(); ionVehicles.Add(ionVehicle1); ionVehicles.Add(ionVehicle2); IResult result = driver.Execute(txn => { return txn.Execute("SELECT * FROM Person WHERE Vehicles = ?", ionVehicles); }); foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // Prints: // { // GovId: "TOYENC486FN", // FirstName: "Brent", // Vehicles: [ // { // Make: "Volkswagen", // Model: "Golf" // }, // { // Make: "Honda", // Model: "Civic" // } // ] // } }

Dokumente werden eingefügt

Im folgenden Codebeispiel werden Ion-Datentypen eingefügt.

string govId = "TOYENC486FH"; Person person = new Person { GovId = "TOYENC486FH", FirstName = "Brent" }; await driver.Execute(async txn => { // Check if a document with GovId:TOYENC486FH exists // This is critical to make this transaction idempotent IAsyncResult<Person> result = await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE GovId = ?", govId)); // Check if there is a record in the cursor. int count = await result.CountAsync(); if (count > 0) { // Document already exists, no need to insert return; } // Insert the document. await txn.Execute(txn.Query<Document>("INSERT INTO Person ?", person)); });
Async
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionPerson = valueFactory.NewEmptyStruct(); ionPerson.SetField("GovId", valueFactory.NewString("TOYENC486FH")); ionPerson.SetField("FirstName", valueFactory.NewString("Brent")); await driver.Execute(async txn => { // Check if a document with GovId:TOYENC486FH exists // This is critical to make this transaction idempotent IAsyncResult result = await txn.Execute("SELECT * FROM Person WHERE GovId = ?", ionGovId); // Check if there is a record in the cursor. int count = await result.CountAsync(); if (count > 0) { // Document already exists, no need to insert return; } // Insert the document. await txn.Execute("INSERT INTO Person ?", ionPerson); });
Sync
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionPerson = valueFactory.NewEmptyStruct(); ionPerson.SetField("GovId", valueFactory.NewString("TOYENC486FH")); ionPerson.SetField("FirstName", valueFactory.NewString("Brent")); driver.Execute(txn => { // Check if a document with GovId:TOYENC486FH exists // This is critical to make this transaction idempotent IResult result = txn.Execute("SELECT * FROM Person WHERE GovId = ?", ionGovId); // Check if there is a record in the cursor. int count = result.Count(); if (count > 0) { // Document already exists, no need to insert return; } // Insert the document. txn.Execute("INSERT INTO Person ?", ionPerson); });

Diese Transaktion fügt ein Dokument in die Person Tabelle ein. Vor dem Einfügen wird zunächst geprüft, ob das Dokument bereits in der Tabelle vorhanden ist. Diese Prüfung macht die Transaktion ihrem Wesen nach idempotent. Selbst wenn Sie diese Transaktion mehrmals ausführen, hat sie keine unbeabsichtigten Nebenwirkungen.

Anmerkung

In diesem Beispiel empfehlen wir, einen Index für das GovId Feld zu verwenden, um die Leistung zu optimieren. Wenn ein Index nicht aktiviert istGovId, können Anweisungen eine längere Latenz haben und auch zu OCC Konfliktausnahmen oder Transaktions-Timeouts führen.

Einfügen mehrerer Dokumente in eine Anweisung

Um mehrere Dokumente mit einer einzigen INSERT Anweisung einzufügen, können Sie der Anweisung wie folgt einen List C#-Parameter übergeben.

Person person1 = new Person { FirstName = "Brent", GovId = "TOYENC486FH" }; Person person2 = new Person { FirstName = "Jim", GovId = "ROEE1C1AABH" }; List<Person> people = new List<Person>(); people.Add(person1); people.Add(person2); IAsyncResult<Document> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Document>("INSERT INTO Person ?", people)); }); await foreach (Document row in result) { Console.WriteLine("{ documentId: " + row.DocumentId + " }"); // The statement returns the created documents' ID: // { documentId: 6BFt5eJQDFLBW2aR8LPw42 } // { documentId: K5Zrcb6N3gmIEHgGhwoyKF } }

Um mehrere Dokumente mit einer einzigen INSERT Anweisung einzufügen, können Sie der Anweisung wie folgt einen Parameter vom Typ Ion-Liste übergeben.

Async
IIonValue ionPerson1 = valueFactory.NewEmptyStruct(); ionPerson1.SetField("FirstName", valueFactory.NewString("Brent")); ionPerson1.SetField("GovId", valueFactory.NewString("TOYENC486FH")); IIonValue ionPerson2 = valueFactory.NewEmptyStruct(); ionPerson2.SetField("FirstName", valueFactory.NewString("Jim")); ionPerson2.SetField("GovId", valueFactory.NewString("ROEE1C1AABH")); IIonValue ionPeople = valueFactory.NewEmptyList(); ionPeople.Add(ionPerson1); ionPeople.Add(ionPerson2); IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("INSERT INTO Person ?", ionPeople); }); await foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the created documents' ID: // { // documentId: "6BFt5eJQDFLBW2aR8LPw42" // } // // { // documentId: "K5Zrcb6N3gmIEHgGhwoyKF" // } }
Sync
IIonValue ionPerson1 = valueFactory.NewEmptyStruct(); ionPerson1.SetField("FirstName", valueFactory.NewString("Brent")); ionPerson1.SetField("GovId", valueFactory.NewString("TOYENC486FH")); IIonValue ionPerson2 = valueFactory.NewEmptyStruct(); ionPerson2.SetField("FirstName", valueFactory.NewString("Jim")); ionPerson2.SetField("GovId", valueFactory.NewString("ROEE1C1AABH")); IIonValue ionPeople = valueFactory.NewEmptyList(); ionPeople.Add(ionPerson1); ionPeople.Add(ionPerson2); IResult result = driver.Execute(txn => { return txn.Execute("INSERT INTO Person ?", ionPeople); }); foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the created documents' ID: // { // documentId: "6BFt5eJQDFLBW2aR8LPw42" // } // // { // documentId: "K5Zrcb6N3gmIEHgGhwoyKF" // } }

Wenn Sie eine Ion-Liste übergeben, setzen Sie den Platzhalter für die Variable (?<<...>>) nicht in doppelte spitze Klammern (). In manuellen PartiQL-Anweisungen bezeichnen doppelte spitze Klammern eine ungeordnete Sammlung, die als Tasche bezeichnet wird.

Dokumente werden aktualisiert

string govId = "TOYENC486FH"; string firstName = "John"; IAsyncResult<Document> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Document>("UPDATE Person SET FirstName = ? WHERE GovId = ?", firstName , govId)); }); await foreach (Document row in result) { Console.WriteLine("{ documentId: " + row.DocumentId + " }"); // The statement returns the updated document ID: // { documentId: Djg30Zoltqy5M4BFsA2jSJ } }
Async
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionFirstName = valueFactory.NewString("John"); IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("UPDATE Person SET FirstName = ? WHERE GovId = ?", ionFirstName , ionGovId); }); await foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the updated document ID: // { // documentId: "Djg30Zoltqy5M4BFsA2jSJ" // } }
Sync
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionFirstName = valueFactory.NewString("John"); IResult result = driver.Execute(txn => { return txn.Execute("UPDATE Person SET FirstName = ? WHERE GovId = ?", ionFirstName , ionGovId); }); foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the updated document ID: // { // documentId: "Djg30Zoltqy5M4BFsA2jSJ" // } }
Anmerkung

In diesem Beispiel empfehlen wir, einen Index für das GovId Feld zu verwenden, um die Leistung zu optimieren. Wenn ein Index nicht aktiviert istGovId, können Anweisungen eine längere Latenz haben und auch zu OCC Konfliktausnahmen oder Transaktions-Timeouts führen.

Dokumente löschen

string govId = "TOYENC486FH"; IAsyncResult<Document> result = await driver.Execute(async txn => { return await txn.Execute(txn.Query<Document>("DELETE FROM Person WHERE GovId = ?", govId)); }); await foreach (Document row in result) { Console.WriteLine("{ documentId: " + row.DocumentId + " }"); // The statement returns the updated document ID: // { documentId: Djg30Zoltqy5M4BFsA2jSJ } }
Async
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IAsyncResult result = await driver.Execute(async txn => { return await txn.Execute("DELETE FROM Person WHERE GovId = ?", ionGovId); }); await foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the deleted document ID: // { // documentId: "Djg30Zoltqy5M4BFsA2jSJ" // } }
Sync
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IResult result = driver.Execute(txn => { return txn.Execute("DELETE FROM Person WHERE GovId = ?", ionGovId); }); foreach (IIonValue row in result) { Console.WriteLine(row.ToPrettyString()); // The statement returns the deleted document ID: // { // documentId: "Djg30Zoltqy5M4BFsA2jSJ" // } }
Anmerkung

In diesem Beispiel empfehlen wir, einen Index für das GovId Feld zu verwenden, um die Leistung zu optimieren. Wenn ein Index nicht aktiviert istGovId, können Anweisungen eine längere Latenz haben und auch zu OCC Konfliktausnahmen oder Transaktions-Timeouts führen.

Ausführung mehrerer Anweisungen in einer Transaktion

// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd // set your UPDATE to filter on vin and insured, and check if you updated something or not. public static async Task<bool> InsureVehicle(IAsyncQldbDriver driver, string vin) { return await driver.Execute(async txn => { // Check if the vehicle is insured. Amazon.QLDB.Driver.Generic.IAsyncResult<Vehicle> result = await txn.Execute( txn.Query<Vehicle>("SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", vin)); if (await result.CountAsync() > 0) { // If the vehicle is not insured, insure it. await txn.Execute( txn.Query<Document>("UPDATE Vehicles SET insured = TRUE WHERE vin = ?", vin)); return true; } return false; }); }
Async
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd // set your UPDATE to filter on vin and insured, and check if you updated something or not. public static async Task<bool> InsureVehicle(IAsyncQldbDriver driver, string vin) { ValueFactory valueFactory = new ValueFactory(); IIonValue ionVin = valueFactory.NewString(vin); return await driver.Execute(async txn => { // Check if the vehicle is insured. Amazon.QLDB.Driver.IAsyncResult result = await txn.Execute( "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", ionVin); if (await result.CountAsync() > 0) { // If the vehicle is not insured, insure it. await txn.Execute( "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", ionVin); return true; } return false; }); }

Logik für Wiederholversuche

Hinweise zur integrierten Wiederholungslogik des Treibers finden Sie unterGrundlegendes zur Wiederholungsrichtlinie mit dem Fahrer in Amazon QLDB.

Implementieren von Eindeutigkeitsbeschränkungen

QLDBunterstützt keine eindeutigen Indizes, aber Sie können dieses Verhalten in Ihrer Anwendung implementieren.

Angenommen, Sie möchten eine Eindeutigkeitsbeschränkung für das GovId Feld in der Person Tabelle implementieren. Zu diesem Zweck können Sie eine Transaktion schreiben, die Folgendes tut:

  1. Bestätigen Sie, dass die Tabelle keine vorhandenen Dokumente mit einem angegebenen Wert enthältGovId.

  2. Fügt das Dokument ein, wenn die Assertion erfolgreich ist.

Wenn eine konkurrierende Transaktion gleichzeitig die Assertion besteht, wird nur eine der Transaktionen erfolgreich festgeschrieben. Die andere Transaktion schlägt mit einer OCC Konfliktausnahme fehl.

Das folgende Codebeispiel zeigt, wie diese Eindeutigkeitsbeschränkungslogik implementiert wird.

string govId = "TOYENC486FH"; Person person = new Person { GovId = "TOYENC486FH", FirstName = "Brent" }; await driver.Execute(async txn => { // Check if a document with GovId:TOYENC486FH exists // This is critical to make this transaction idempotent IAsyncResult<Person> result = await txn.Execute(txn.Query<Person>("SELECT * FROM Person WHERE GovId = ?", govId)); // Check if there is a record in the cursor. int count = await result.CountAsync(); if (count > 0) { // Document already exists, no need to insert return; } // Insert the document. await txn.Execute(txn.Query<Document>("INSERT INTO Person ?", person)); });
Async
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionPerson = valueFactory.NewEmptyStruct(); ionPerson.SetField("GovId", valueFactory.NewString("TOYENC486FH")); ionPerson.SetField("FirstName", valueFactory.NewString("Brent")); await driver.Execute(async txn => { // Check if a document with GovId:TOYENC486FH exists // This is critical to make this transaction idempotent IAsyncResult result = await txn.Execute("SELECT * FROM Person WHERE GovId = ?", ionGovId); // Check if there is a record in the cursor. int count = await result.CountAsync(); if (count > 0) { // Document already exists, no need to insert return; } // Insert the document. await txn.Execute("INSERT INTO Person ?", ionPerson); });
Sync
IIonValue ionGovId = valueFactory.NewString("TOYENC486FH"); IIonValue ionPerson = valueFactory.NewEmptyStruct(); ionPerson.SetField("GovId", valueFactory.NewString("TOYENC486FH")); ionPerson.SetField("FirstName", valueFactory.NewString("Brent")); driver.Execute(txn => { // Check if a document with GovId:TOYENC486FH exists // This is critical to make this transaction idempotent IResult result = txn.Execute("SELECT * FROM Person WHERE GovId = ?", ionGovId); // Check if there is a record in the cursor. int count = result.Count(); if (count > 0) { // Document already exists, no need to insert return; } // Insert the document. txn.Execute("INSERT INTO Person ?", ionPerson); });
Anmerkung

In diesem Beispiel empfehlen wir, einen Index für das GovId Feld zu verwenden, um die Leistung zu optimieren. Wenn ein Index nicht aktiviert istGovId, können Anweisungen eine längere Latenz haben und auch zu OCC Konfliktausnahmen oder Transaktions-Timeouts führen.

Arbeiten mit Amazon Ion

Es gibt mehrere Möglichkeiten, Amazon Ion-Daten zu verarbeitenQLDB. Sie können die Ionen-Bibliothek verwenden, um Ion-Werte zu erstellen und zu ändern. Oder Sie können den Ion-Objektmapper verwenden, um einfache alte CLR C#-Objekte (POCO) Ion-Werten zuzuordnen. Version 1.3.0 des Treibers für. QLDB NETführt Unterstützung für den Ion Object Mapper ein.

Die folgenden Abschnitte enthalten Codebeispiele für die Verarbeitung von Ion-Daten mit beiden Techniken.

Das Ion-Modul importieren

using Amazon.IonObjectMapper;
using Amazon.IonDotnet.Builders;

Ionentypen erstellen

Das folgende Codebeispiel zeigt, wie mit dem Ion-Objektmapper Ion-Werte aus C#-Objekten erstellt werden.

// Assumes that Person class is defined as follows: // public class Person // { // public string FirstName { get; set; } // public int Age { get; set; } // } // Initialize the Ion Object Mapper IonSerializer ionSerializer = new IonSerializer(); // The C# object to be serialized Person person = new Person { FirstName = "John", Age = 13 }; // Serialize the C# object into stream using the Ion Object Mapper Stream stream = ionSerializer.Serialize(person); // Load will take in stream and return a datagram; a top level container of Ion values. IIonValue ionDatagram = IonLoader.Default.Load(stream); // To get the Ion value within the datagram, we call GetElementAt(0). IIonValue ionPerson = ionDatagram.GetElementAt(0); Console.WriteLine(ionPerson.GetField("firstName").StringValue); Console.WriteLine(ionPerson.GetField("age").IntValue);

Die folgenden Codebeispiele zeigen die beiden Möglichkeiten, Ion-Werte mithilfe der Ionen-Bibliothek zu erstellen.

Verwenden von ValueFactory

using Amazon.IonDotnet.Tree; using Amazon.IonDotnet.Tree.Impl; IValueFactory valueFactory = new ValueFactory(); IIonValue ionPerson = valueFactory.NewEmptyStruct(); ionPerson.SetField("firstName", valueFactory.NewString("John")); ionPerson.SetField("age", valueFactory.NewInt(13)); Console.WriteLine(ionPerson.GetField("firstName").StringValue); Console.WriteLine(ionPerson.GetField("age").IntValue);

Verwenden von IonLoader

using Amazon.IonDotnet.Builders; using Amazon.IonDotnet.Tree; // Load will take in Ion text and return a datagram; a top level container of Ion values. IIonValue ionDatagram = IonLoader.Default.Load("{firstName: \"John\", age: 13}"); // To get the Ion value within the datagram, we call GetElementAt(0). IIonValue ionPerson = ionDatagram.GetElementAt(0); Console.WriteLine(ionPerson.GetField("firstName").StringValue); Console.WriteLine(ionPerson.GetField("age").IntValue);

Einen Ion-Binär-Dump abrufen

// Initialize the Ion Object Mapper with Ion binary serialization format IonSerializer ionSerializer = new IonSerializer(new IonSerializationOptions { Format = IonSerializationFormat.BINARY }); // The C# object to be serialized Person person = new Person { FirstName = "John", Age = 13 }; MemoryStream stream = (MemoryStream) ionSerializer.Serialize(person); Console.WriteLine(BitConverter.ToString(stream.ToArray()));
// ionObject is an Ion struct MemoryStream stream = new MemoryStream(); using (var writer = IonBinaryWriterBuilder.Build(stream)) { ionObject.WriteTo(writer); writer.Finish(); } Console.WriteLine(BitConverter.ToString(stream.ToArray()));

Einen Ion-Textdump abrufen

// Initialize the Ion Object Mapper IonSerializer ionSerializer = new IonSerializer(new IonSerializationOptions { Format = IonSerializationFormat.TEXT }); // The C# object to be serialized Person person = new Person { FirstName = "John", Age = 13 }; MemoryStream stream = (MemoryStream) ionSerializer.Serialize(person); Console.WriteLine(System.Text.Encoding.UTF8.GetString(stream.ToArray()));
// ionObject is an Ion struct StringWriter sw = new StringWriter(); using (var writer = IonTextWriterBuilder.Build(sw)) { ionObject.WriteTo(writer); writer.Finish(); } Console.WriteLine(sw.ToString());

Weitere Informationen zur Arbeit mit Ion finden Sie in der Amazon Ion-Dokumentation unter GitHub. Weitere Codebeispiele für die Arbeit mit Ion in QLDB finden Sie unterArbeiten mit Amazon Ion-Datentypen in Amazon QLDB.