演習 - 新しい項目を作成する
.NET 用 Azure Cosmos DB SDK を使って、コンテナー内に項目を作成できることを思い出してください。 このプロジェクトの製品コンテナーには、個々の "製品" 項目と、各カテゴリに関する特別な "カテゴリ" 項目の両方が含まれます。 このアプリケーションでは、次の 2 つのケースを処理します。
- カテゴリが空の場合は、そのカテゴリの項目を個別に作成するだけで問題ありません。 作成する関連製品項目はありません。
- カテゴリに関連製品が含まれる場合に、カテゴリ項目とそれに関連する製品項目を同時に作成する必要があります。
ここでの重要な要件は次の 2 つです。
- 1 つの操作として項目を個別に作成する
- トランザクション バッチを使用して複数の関連項目を作成する
この演習を完了すると、プロジェクトには、コンテナー内に個別に、またはバッチとして項目を作成するロジックが含まれるようになります。
コンテナーに個々の項目を追加する
Azure Cosmos DB では、コンテナーの項目を作成、置換、またはアップサートできます。 項目を "作成" するには、項目に一意の識別子が設定されている必要があります。 項目を "置換" するには、項目が既に存在している必要があります。 "アップサート" は両方の機能を組み合わせたものであり、一意の識別子を確認した後、項目を置換または作成します。 このプロジェクトでは、エラーなしでアプリを複数回実行できるようにする必要があり、明らかに "アップサート" を選ぶことになります。 最初の項目では、製品が関連付けられていないカテゴリを作成します。 ここで、手動で作成されたカテゴリを使って 1 つのアップサート操作を実装します。
Program.cs ファイルをさらにもう一度開きます。
次の値を使って、
goggles
という名前の新しい Category インスタンスを作成します。プロパティ 値 id ef7fa0f1-0e9d-4435-aaaf-a778179a94ad
categoryId gear-snow-goggles
Category goggles = new( Id: "ef7fa0f1-0e9d-4435-aaaf-a778179a94ad", CategoryId: "gear-snow-goggles" );
前に作成した Category インスタンスの
categoryId
プロパティと同じ値を使って、新しい PartitionKey インスタンスを作成します。PartitionKey gogglesKey = new("gear-snow-goggles");
UpsertItemAsync メソッドを使い、作成する項目のオブジェクトとパーティション キー値を渡して、項目を作成または置換します。
Category result = await container.UpsertItemAsync(goggles, gogglesKey);
項目の一意識別子や項目の種類など、
result
のさまざまなプロパティをコンソールに出力します。Console.WriteLine($"[New item created]:\t{result.Id}\t(Type: {result.Type})");
次の値を使って、
helmets
という名前の新しい Category インスタンスを作成します。プロパティ 値 id 91f79374-8611-4505-9c28-3bbbf1aa7df7
categoryId gear-climb-helmets
Category helmets = new( Id: "91f79374-8611-4505-9c28-3bbbf1aa7df7", CategoryId: "gear-climb-helmets" );
前に作成した Category インスタンスの
categoryId
プロパティと同じ値を使って、新しい PartitionKey インスタンスを作成します。PartitionKey helmetsKey = new("gear-climb-helmets");
UpsertItemAsync メソッドを使って、項目を作成または置換します。 作成する項目のオブジェクトとパーティション キーの値を渡します。 ItemResponse<T> 型のオブジェクトを返します。
ItemResponse<Category> response = await container.UpsertItemAsync(helmets, helmetsKey);
次のような
response
のさまざまなプロパティをコンソールに出力します: 基になる項目の一意識別子、基になる項目の型、1 秒あたりの要求の料金の増分。Console.WriteLine($"[New item created]:\t{response.Resource.Id}\t(Type: {response.Resource.Type})\t(RUs: {response.RequestCharge})");
Program.cs ファイルを保存します。
複数の操作をトランザクション バッチとして実装する
次に、カテゴリと共に複数の製品を作成するシナリオを考えます。 製品が作成されていても、カテゴリが存在しない場合、それらの製品はほとんど役に立ちません。 複数の項目を作成するときは、すべてが 1 つのまとまった単位として成功または失敗するように、トランザクションを使って複数の "ポイント" 操作をグループ化できます。 ここでのシナリオに戻り、いくつかのテント製品を含むアウトドア テントのカテゴリを作成する必要があります。 製品項目を何も含まない 1 つのカテゴリ項目が既に存在します。 最終的には次のようになります。
このセクションでは、tents
カテゴリとそれに関連する製品をまとめて作成するトランザクショナル バッチを作成します。
Program.cs で、次の値を使って、
tents
という名前の新しい Category インスタンスを作成します。プロパティ 値 id 5df21ec5-813c-423e-9ee9-1a2aaead0be4
categoryId gear-camp-tents
Category tents = new( Id: "5df21ec5-813c-423e-9ee9-1a2aaead0be4", CategoryId: "gear-camp-tents" );
これらの値を使って、Product 型の 4 つのインスタンスを作成します。
プロパティ cirroa
kuloar
mammatin
nimbolo
Id e8dddee4-9f43-4d15-9b08-0d7f36adcac8
e6f87b8d-8cd7-4ade-a005-14d3e2fbd1aa
f7653468-c4b8-47c9-97ff-451ee55f4fd5
6e3b7275-57d4-4418-914d-14d1baca0979
CategoryId gear-camp-tents
gear-camp-tents
gear-camp-tents
gear-camp-tents
名前 Cirroa Tent
Kuloar Tent
Mammatin Tent
Nimbolo Tent
価格 490.00
530.00
0.00
330.00
Archived false
false
true
false
Quantity 15
8
0
35
Product cirroa = new( Id: "e8dddee4-9f43-4d15-9b08-0d7f36adcac8", CategoryId: "gear-camp-tents" ){ Name = "Cirroa Tent", Price = 490.00m, Archived = false, Quantity = 15 };
Product kuloar = new( Id: "e6f87b8d-8cd7-4ade-a005-14d3e2fbd1aa", CategoryId: "gear-camp-tents" ){ Name = "Kuloar Tent", Price = 530.00m, Archived = false, Quantity = 8 };
Product mammatin = new( Id: "f7653468-c4b8-47c9-97ff-451ee55f4fd5", CategoryId: "gear-camp-tents" ){ Name = "Mammatin Tent", Price = 0.00m, Archived = true, Quantity = 0 };
Product nimbolo = new( Id: "6e3b7275-57d4-4418-914d-14d1baca0979", CategoryId: "gear-camp-tents" ){ Name = "Nimbolo Tent", Price = 330.00m, Archived = false, Quantity = 35 };
ここでは、
gear-camp-tents
の値を使って、新しい PartitionKey インスタンスを作成します。PartitionKey tentsKey = new("gear-camp-tents");
CreateTransactionalBatch(PartitionKey) メソッドを使って、
gear-camp-tents
パーティション キー値にスコープ設定された新しいトランザクション バッチを作成します。 fluent 構文を使って、カテゴリとすべての関連製品に必要な項目をコンテナーに作成するための、5 つの "アップサート" 操作を追加します。TransactionalBatch batch = container.CreateTransactionalBatch(tentsKey) .UpsertItem<Category>(tents) .UpsertItem<Product>(cirroa) .UpsertItem<Product>(kuloar) .UpsertItem<Product>(mammatin) .UpsertItem<Product>(nimbolo);
バッチ操作を開始していることを示すメッセージをコンソールに出力します。
Console.WriteLine("[Batch started]");
TransactionalBatch.ExecuteAsync
メソッドを使って、バッチを実行し、特殊な応答の種類を返します。using TransactionalBatchResponse batchResponse = await batch.ExecuteAsync();
for ループを使って、応答内のすべての項目を反復処理します。 最初に、
Item
基底クラスをジェネリックとして使って、各項目をTransactionalBatchOperationResult
型に変換します。 次に、応答オブジェクトの一意識別子と型を出力します。for (int i = 0; i < batchResponse.Count; i++) { TransactionalBatchOperationResult<Item> batchResult = batchResponse.GetOperationResultAtIndex<Item>(i); Console.WriteLine($"[New item created]:\t{batchResult.Resource.Id}\t(Type: {batchResult.Resource.Type})"); }
バッチが完了したことを示す別のメッセージをコンソールに出力します。 このメッセージには、バッチ全体の要求使用量を含めます。
Console.WriteLine($"[Batch completed]:\t(RUs: {batchResponse.RequestCharge})");
Program.cs ファイルを保存します。
作業を確認
これでアプリは、複数の項目を作成するようになり、例外を発生させずに複数回実行できる回復性を持つように設計されました。 ここで、アプリケーションを実行し、新しく作成された 6 つの各項目の一意識別子の出力を調べます。
ターミナルで .NET アプリケーションを実行します。
dotnet run
アプリケーションを実行した出力を確認します。 出力は、次の例と一致しているはずです。
... [New item created]: ef7fa0f1-0e9d-4435-aaaf-a778179a94ad (Type: Category) [New item created]: 91f79374-8611-4505-9c28-3bbbf1aa7df7 (Type: Category) (RUs: 10.29) [Batch started] [New item created]: 5df21ec5-813c-423e-9ee9-1a2aaead0be4 (Type: Category) [New item created]: e8dddee4-9f43-4d15-9b08-0d7f36adcac8 (Type: Product) [New item created]: e6f87b8d-8cd7-4ade-a005-14d3e2fbd1aa (Type: Product) [New item created]: f7653468-c4b8-47c9-97ff-451ee55f4fd5 (Type: Product) [New item created]: 6e3b7275-57d4-4418-914d-14d1baca0979 (Type: Product) [Batch completed]: (RUs: 36.76)
ヒント
この出力例で示されている RU は、実際の出力と異なる場合があります。