Overview
このガイドでは、EF Core Provider アプリケーションでトランザクションを使用する方法を学ぶことができます。トランザクションは一連の書き込み操作をラップします。トランザクション内の操作が 1 つでも失敗すると、プロバイダーはトランザクション内のすべての変更をロールバックします。この動作により、データの整合性が確保されます。
EF Core プロバイダーは次のトランザクション モードをサポートしています。
Implicit transactions: The provider automatically wraps calls to the
SaveChanges()andSaveChangesAsync()methods in a transaction. See Configure Implicit Transactions to learn how to configure or disable this behavior.Explicit transactions: You call the
Database.BeginTransaction()method to manually begin a transaction, then commit or roll back the transaction by callingCommit()orRollback().
サンプル データ
このガイドの例では、 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; } }
This collection is from the sample datasets provided by Atlas. See the Get Started with the EF Core Provider guide to learn how to create a free MongoDB cluster and load this sample data.
要件と制限事項
トランザクションを使用する前に、以下の要件と制約事項に留意してください。
Transactions require a MongoDB Server deployment that supports multi-document transactions, such as a replica set or sharded cluster. If your application tries to start a transaction on a standalone deployment, the provider throws a
NotSupportedException. To prevent this, setAutoTransactionBehavior.Neveras described in Configure Implicit Transactions.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();
To learn more about read concern, write concern, and read preference, see Read Concern, Write Concern, and Read Preference.
トランザクションの制限
トランザクションを使用する場合、次の制限と注意事項が適用されます。
自動トランザクションは、配置がサポートしていない場合にのみ無効にしてください。自動トランザクションを無効にすると、データの不整合が発生し、楽観的同時実行を使用できなくなります。
MongoDB Server はネストされたトランザクションをサポートしません。トランザクションが既にアクティブな状態で
BeginTransaction()またはBeginTransactionAsync()を呼び出すと、プロバイダーはInvalidOperationExceptionをスローします。MongoDB Server はトランザクションの保存ポイントをサポートしません。トランザクション全体をコミットまたはロールバックする必要があります。
デフォルトでは、MongoDB Server は
transactionLifetimeLimitSecondsサーバー パラメーターによって制御されるように、60 秒を超えて実行されるトランザクションを中止します。この制限は、暗黙的なトランザクションと明示的なトランザクションの両方に適用されます。トランザクションがこの時間制限を超えると、MongoDB Server はトランザクションを中止し、プロバイダーはエラーをスローします。外部 API 呼び出しなどの時間のかかる操作は、トランザクション内で行わないでください。If MongoDB Server experiences a network interruption or must perform a replica set election, it might return a
TransientTransactionErrorerror. In these cases, the EF Core Provider doesn't automatically retry the transaction. To learn more about transient transaction errors and retry strategies, see Transaction Error Handling.
詳細情報
このガイドの概念の詳細については、次のリソースを参照してください。
このガイドで使用されているメソッドの詳細については、次の .NET API ドキュメントを参照してください。