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
Inhalt
- Der Treiber wird importiert
- Der Treiber wird instanziiert
- CRUDOperationen
- 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.
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. 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.
Inhalt
Erstellen von Tabellen
Erstellen von Indizes
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 // }, // ] // } }
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.
Das folgende Codebeispiel verwendet mehrere Abfrageparameter.
Das folgende Codebeispiel verwendet eine Liste von Abfrageparametern.
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.
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)); });
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.
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 } }
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 } }
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; }); }
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:
-
Bestätigen Sie, dass die Tabelle keine vorhandenen Dokumente mit einem angegebenen Wert enthält
GovId
. -
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)); });
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
Die folgenden Abschnitte enthalten Codebeispiele für die Verarbeitung von Ion-Daten mit beiden Techniken.
Inhalt
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