本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
Amazon QLDB 驅動程序. NET— 食譜參考
本參考指南顯示 Amazon QLDB 驅動程式的常見使用案例。 NET。它提供 C# 程式碼範例,示範如何使用驅動程式來執行基本的建立、讀取、更新和 delete (CRUD) 作業。它還包括用於處理 Amazon Ion 資料的程式碼範例。此外,本指南還重點介紹了使交易冪等和實施唯一性約束的最佳實踐。
匯入驅動程式
下列程式碼範例會匯入驅動程式。
using Amazon.QLDB.Driver;
using Amazon.QLDB.Driver.Generic;
using Amazon.QLDB.Driver.Serialization;
using Amazon.QLDB.Driver;
using Amazon.IonDotnet.Builders;
實例化驅動程序
下列程式碼範例會建立使用預設設定連線至指定分類帳名稱的驅動程式執行環境。
- 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();
CRUD操作
QLDB在交易中執行建立、讀取、更新和刪除 (CRUD) 作業。
使交易冪等
我們建議您將寫入事務設為冪等,以避免在重試的情況下出現任何意外的副作用。如果事務可以運行多次並每次產生相同的結果,則事務是冪等的。
例如,假設將文件插入名為的資料表中的交易Person
。事務應該首先檢查文檔是否已經存在於表中。如果沒有此檢查,表格最終可能會出現重複的文件。
假設成QLDB功地在服務器端提交事務,但客戶端在等待響應時超時。如果事務不是冪等的,則在重試的情況下,可以多次插入相同的文檔。
使用索引來避免全表掃描
我們也建議您在索引欄位或文件 ID 上使用相等運算子來執行具有述WHERE
詞子句的陳述式;例如,WHERE indexedField = 123
或WHERE indexedField IN (456, 789)
。如果沒有此索引查找,則QLDB需要進行表掃描,這可能會導致事務超時或樂觀的並發控制(OCC)衝突。
如需有關 OCC 的詳細資訊,請參閱 Amazon QLDB 并发模型。
隱含建立的交易
Amazon。 QLDB. 驅動程式。 IQldbDriver.Execute 方法接受接收 Amazon 實例的 lambda 函數。 QLDB. 驅動程式。 TransactionExecutor,您可以使用它來執行陳述式。TransactionExecutor
封裝隱含建立之交易的執行個體。
您可以使用交易執行程Execute
式的方法,在 lambda 函數中執行陳述式。當 lambda 函數返回時,驅動程序隱式地提交交易。
下列各節說明如何執行基本CRUD作業、指定自訂重試邏輯,以及實作唯一性條件約束。
建立資料表
- 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"
// }
}
建立索引
- 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"
// }
}
閱讀文件
// 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.
}
當您在沒有索引查閱的情況下執行查詢時,會叫用完整資料表掃描。在此範例中,我們建議在GovId
欄位上建立索引以最佳化效能。如果沒有開啟索引GovId
,查詢可能會有更多延遲,也可能導致OCC衝突例外狀況或交易逾時。
使用查詢參數
下列程式碼範例會使用 C# 型別查詢參數。
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.
}
下列程式碼範例會使用多個 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.
}
下列程式碼範例會使用 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.
}
下列程式碼範例會使用 C# 清單做為值。
// 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.
}
當您在沒有索引查閱的情況下執行查詢時,會叫用完整資料表掃描。在此範例中,我們建議在GovId
欄位上建立索引以最佳化效能。如果沒有開啟索引GovId
,查詢可能會有更多延遲,也可能導致OCC衝突例外狀況或交易逾時。
下列程式碼範例會使用 Ion 型別查詢參數。
- 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.
}
下列程式碼範例會使用多個查詢參數。
- 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.
}
下列程式碼範例使用查詢參數清單。
- 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.
}
下列程式碼範例會使用 Ion 清單做為值。若要進一步瞭解如何使用不同離子類型,請參閱使用 Amazon 離子數據類型在 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"
// }
// ]
// }
}
插入文件
下列程式碼範例會插入 Ion 資料型別。
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);
});
此事務將一個文檔插入到Person
表中。在插入之前,它會先檢查文件是否已存在於表格中。這個檢查使事務本質上是冪等的。即使您多次運行此事務,也不會造成任何意外的副作用。
在此範例中,我們建議在GovId
欄位上建立索引以最佳化效能。如果沒有開啟索引GovId
,陳述式可能會有更多延遲,也可能導致OCC衝突例外狀況或交易逾時。
在一個語句中插入多個文檔
若要使用單一INSERT陳述式插入多個文件,您可以將 C# List
參數傳遞至陳述式,如下所示。
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 }
}
要通過使用單個INSERT語句插入多個文檔,可以傳遞離子列表類型的參數到語句如下。
- 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"
// }
}
傳遞離子清單時,您不會將變數預留位置 (?
<<...>>
) 括在雙尖括號 () 中。在手動 PartiQL 陳述式中,雙角括號表示稱為袋子的無序集合。
更新文件
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"
// }
}
在此範例中,我們建議在GovId
欄位上建立索引以最佳化效能。如果沒有開啟索引GovId
,陳述式可能會有更多延遲,也可能導致OCC衝突例外狀況或交易逾時。
刪除文件
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"
// }
}
在此範例中,我們建議在GovId
欄位上建立索引以最佳化效能。如果沒有開啟索引GovId
,陳述式可能會有更多延遲,也可能導致OCC衝突例外狀況或交易逾時。
在交易中執行多個陳述式
// 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;
});
}
重試邏輯
如需驅動程式內建重試邏輯的詳細資訊,請參閱了解 Amazon 中的驅動程序的重試政策 QLDB。
實施唯一性約束
QLDB不支持唯一索引,但您可以在應用程序中實現此行為。
假設您要在Person
表中的GovId
字段上實現唯一性約束。要做到這一點,你可以寫一個事務,執行以下操作:
-
斷言表沒有具有指定GovId
的現有文檔。
-
插入文檔,如果斷言通過。
如果競爭交易同時通過斷言,則只有其中一個交易將成功提交。另一個交易會失敗,並出現OCC衝突例外狀況。
下列程式碼範例會示範如何實作此唯一性條件約束邏輯。
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);
});
在此範例中,我們建議在GovId
欄位上建立索引以最佳化效能。如果沒有開啟索引GovId
,陳述式可能會有更多延遲,也可能導致OCC衝突例外狀況或交易逾時。
與 Amazon 離子工作
有多種方法可以在中處理 Amazon 離子數據QLDB。您可以使用 I on 元件庫來建立和修改 Ion 值。或者,您可以使用 Ion 對象映射器將 C# 普通舊對CLR象(POCO)映射到 Ion 值。QLDB驅動程式的 1.3.0 版本。 NET引入了對 Ion 對象映射器的支持。
以下各節提供使用這兩種技術處理離子資料的程式碼範例。
匯入離子模組
using Amazon.IonObjectMapper;
using Amazon.IonDotnet.Builders;
建立離子類型
下列程式碼範例會示範如何使用 Ion 物件對應程式,從 C# 物件建立 Ion 值。
// 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);
下列程式碼範例會示範使用 Ion 程式庫建立 Ion 值的兩種方式。
使用 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);
使用 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);
獲取離子二進制轉儲
// 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()));
獲取離子文本轉儲
// 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());
如需使用 Ion 的詳細資訊,請參閱上的 Amazon Ion 文件 GitHub。如需中使用 Ion 的更多程式碼範例QLDB,請參閱使用 Amazon 離子數據類型在 Amazon QLDB。