Overview
このガイドでは、EF Core Provider アプリケーションでトランザクションを使用する方法を学ぶことができます。トランザクションは一連の書き込み操作をラップします。トランザクション内の操作が 1 つでも失敗すると、プロバイダーはトランザクション内のすべての変更をロールバックします。この動作により、データの整合性が確保されます。
EF Core プロバイダーは次のトランザクション モードをサポートしています。
暗黙的なトランザクション: プロバイダーは、
SaveChanges()メソッドとSaveChangesAsync()メソッドへの呼び出しを自動的にトランザクションでラップします。この動作を構成または無効にする方法については、暗黙的なトランザクションの構成を参照してください。明示的なトランザクション:
Database.BeginTransaction()メソッドを呼び出してトランザクションを手動で開始し、Commit()またはRollback()を呼び出してトランザクションをコミットまたはロールバックします。
サンプル データ
このガイドの例では、 sample_guidesデータベースの planetsコレクションを使用します。このコレクションのドキュメントは、次の Planetクラスをモデルとして使用します。
public class Planet { public ObjectId _id { get; set; } public string name { get; set; } = null!; public int orderFromSun { get; set; } public bool hasRings { get; set; } }
このコレクションは、サンプルデータセットから構成されています。無料のMongoDBクラスターを作成し、このサンプルデータをロードする方法については、クイックスタートガイドを参照してください。
要件と制限事項
トランザクションを使用する前に、以下の要件と制約事項に留意してください。
トランザクションには、レプリカセットやシャーディングされたクラスターなどのマルチドキュメントトランザクションをサポートするMongoDB Server の配置が必要です。アプリケーションがスタンドアロン配置でトランザクションを開始しようとすると、プロバイダーは
NotSupportedExceptionをスローします。これを防ぐには、暗黙的トランザクションの構成に記述されているようにAutoTransactionBehavior.Neverを設定します。EF Core プロバイダーは、
System.Transactions.TransactionScopeによって作成されるような .NET 環境トランザクションをサポートしません。環境トランザクションを使用しようとすると、プロバイダーは例外をスローします。代わりに暗黙的または明示的なトランザクションを使用します。
暗黙的なトランザクション
デフォルトで、EF Core プロバイダーは複数の ルート エンティティ が影響を受ける場合、SaveChanges() と SaveChangesAsync() の呼び出しを自動的にトランザクションでラップします。ルート エンティティは、コレクション内のトップレベル ドキュメントです。これは、別のドキュメント内に保存される所有型または埋め込み型とは対照的です。
次の例では、単一の SaveChanges() 呼び出しで 2 つの惑星を挿入しています。この操作は複数のルートエンティティに影響するため、プロバイダーは自動的にトランザクションでラップします。いずれかの挿入が失敗した場合、プロバイダーは両方の変更をロールバックします。
SynchronousAsynchronous対応するコードを表示するには、 タブまたは タブを選択します。
dbContext.Planets.AddRange( new Planet { Name = "Mercury" }, new Planet { Name = "Venus" } ); // Both inserts succeed or both are rolled back dbContext.SaveChanges();
dbContext.Planets.AddRange( new Planet { Name = "Mercury" }, new Planet { Name = "Venus" } ); // Both inserts succeed or both are rolled back await dbContext.SaveChangesAsync();
暗黙的トランザクションの設定
DbContextオブジェクトのDatabase.AutoTransactionBehaviorプロパティは、プロバイダーが暗黙的なトランザクションを使用するタイミングを制御します。このプロパティは、AutoTransactionBehavior列挙から値を受け入れます。これには次の値が含まれます。
値 | 説明 |
|---|---|
| プロバイダーは、 |
| プロバイダーは、単一エンティティ操作ですら、常にトランザクションを使用します。 |
| プロバイダーはトランザクションを使用しません。 |
次の例に示すように、SaveChanges() または SaveChangesAsync() メソッドを呼び出す前に、いつでもこのプロパティを設定できます。対応するコードを表示するには、Synchronous タブまたは Asynchronous タブを選択します。
dbContext.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; // This SaveChanges() call will not use a transaction dbContext.Planets.Add(new Planet { Name = "Mars" }); dbContext.SaveChanges();
dbContext.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; // This SaveChangesAsync() call will not use a transaction dbContext.Planets.Add(new Planet { Name = "Mars" }); await dbContext.SaveChangesAsync();
明示的なトランザクション
明示的なトランザクションを使用して、複数の SaveChanges() 呼び出しとその他の操作を 1 つのアトミックな作業単位にグループ化できます。明示的なトランザクションを開始するには、Database.BeginTransaction() または Database.BeginTransactionAsync() メソッドを呼び出します。操作を実行した後、Commit() または CommitAsync() を呼び出してトランザクションを完了します。
次の例では、複数の操作を 1 つのトランザクションにまとめることで、このパターンを示しています。いずれかの操作で例外がスローされた場合、プロバイダーはトランザクション内のすべての変更を自動的にロールバックします。SynchronousAsynchronous対応するコードを表示するには、 タブまたは タブを選択します。
using var transaction = dbContext.Database.BeginTransaction(); var planet = dbContext.Planets.First(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; dbContext.SaveChanges(); dbContext.Planets.Add(new Planet { Name = "Venus" }); dbContext.SaveChanges(); transaction.Commit();
await using var transaction = await dbContext.Database.BeginTransactionAsync(); var planet = await dbContext.Planets.FirstAsync(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; await dbContext.SaveChangesAsync(); dbContext.Planets.Add(new Planet { Name = "Venus" }); await dbContext.SaveChangesAsync(); await transaction.CommitAsync();
Tip
マニュアルなロールバック
このページの例では、using 宣言を使用してトランザクションを自動的にロールバックし、トランザクション オブジェクトを破棄します。トランザクションを手動でロールバックするには、catch ブロックで Rollback() または RollbackAsync() メソッドを呼び出します。
明示的なトランザクションの構成
BeginTransaction() または BeginTransactionAsync() メソッドに TransactionOptions オブジェクトを渡すと、トランザクションの読み取り保証 (read concern)、書込み保証 (write concern)、読み込み設定 (read preference)、および最大コミット時間を構成できます。
TransactionOptionsクラスには次のプロパティがあります。
プロパティ | タイプ | 説明 |
|---|---|---|
|
| トランザクション内の最初のコマンドに対する読み取り保証 (read concern)。デフォルト値は |
|
| トランザクション内の読み取り操作の読み込み設定 (read preference)。トランザクションはプライマリから読み取る必要があります。デフォルト値は |
|
|
|
|
| 1 つの |
次の例では、ReadConcern の Majority を使用してトランザクションを開始します。対応するコードを表示するには、Synchronous タブまたは Asynchronous タブを選択します。
var options = new TransactionOptions( readConcern: new Optional<ReadConcern>(ReadConcern.Majority) ); using var transaction = dbContext.Database.BeginTransaction(options); var planet = dbContext.Planets.First(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; dbContext.SaveChanges(); transaction.Commit();
var options = new TransactionOptions( readConcern: new Optional<ReadConcern>(ReadConcern.Majority) ); await using var transaction = await dbContext.Database.BeginTransactionAsync(options); var planet = await dbContext.Planets.FirstAsync(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; await dbContext.SaveChangesAsync(); await transaction.CommitAsync();
読み取り保証 (read concern)、書込み保証 (write concern)、読み込み設定 (read preference)の詳細については、「読み取り保証 (read concern)」、「書込み保証 (write concern)」、「読み込み設定 (read preference)」を参照してください。
トランザクションの制限
トランザクションを使用する場合、次の制限と注意事項が適用されます。
自動トランザクションは、配置がサポートしていない場合にのみ無効にしてください。自動トランザクションを無効にすると、データの不整合が発生し、楽観的同時実行を使用できなくなります。
MongoDB Server はネストされたトランザクションをサポートしません。トランザクションが既にアクティブな状態で
BeginTransaction()またはBeginTransactionAsync()を呼び出すと、プロバイダーはInvalidOperationExceptionをスローします。MongoDB Server はトランザクションの保存ポイントをサポートしません。トランザクション全体をコミットまたはロールバックする必要があります。
デフォルトでは、MongoDB Server は
transactionLifetimeLimitSecondsサーバー パラメーターによって制御されるように、60 秒を超えて実行されるトランザクションを中止します。この制限は、暗黙的なトランザクションと明示的なトランザクションの両方に適用されます。トランザクションがこの時間制限を超えると、MongoDB Server はトランザクションを中止し、プロバイダーはエラーをスローします。外部 API 呼び出しなどの時間のかかる操作は、トランザクション内で行わないでください。MongoDB Server でネットワーク中断が発生した場合、またはレプリカセットの選挙を実行する必要がある場合、
TransientTransactionErrorエラーが返される可能性があります。このような場合、EF Core Provider はトランザクションを自動的に再試行しません。一時的なトランザクション エラーと再試行戦略の詳細については、「トランザクション エラー処理」を参照してください。
詳細情報
このガイドの概念の詳細については、次のリソースを参照してください。
このガイドで使用されているメソッドの詳細については、次の .NET API ドキュメントを参照してください。