Entity Frameworkにトランザクション管理を任せる
SaveChanges()やExecuteSqlCommand()が呼ばれるたびにトランザクションが作成されます。
using (var context = new SampleContext())
{
// トランザクション開始
context.Database.ExecuteSqlCommand(
"UPDATE Samples SET Name = 'Hoge' WHERE Id= 1"
);
context.Samples.Add(new Sample());
context.SaveChanges(); // トランザクション開始
context.Samples.Add(new Sample());
context.SaveChanges(); // トランザクション開始
}
自分でトランザクションを開始する
BeginTransaction()で複数のSaveChanges()やExecuteSqlCommand()などをひとつのトランザクション内で実行できます。
using (var context = new SampleContext())
using (var tran = context.Database.BeginTransaction()) // トランザクション開始
{
try {
context.Database.ExecuteSqlCommand(
"UPDATE Samples SET Name = 'Hoge' WHERE Id = 1"
);
context.Samples.Add(new Sample());
context.SaveChanges();
context.Samples.Add(new Sample());
context.SaveChanges();
tran.Commit();
}
catch (Exception)
{
tran.Rollback();
throw;
}
}
TransactionScopeを使っても同様のことができますが、
Azure SQL DBでサポートされていない分散トランザクションになってしまうことがあったり、
後述のUseTransactionと組み合わせられないため、
Entity Framework 6ではBeginTransaction()が推奨されています。
既存のトランザクションを使用する
UseTransaction()で既存のトランザクションを使用できます。
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var tran = conn.BeginTransaction()) // トランザクション開始
{
try {
var command = new SqlCommand(sql, conn, tran);
sqlCommand.ExecuteNonQuery();
using (var context = new SampleContext(
conn, contextOwnsConnection: false))
{
context.Database.UseTransaction(tran);
context.Samples.Add(new Sample());
context.SaveChanges();
}
tran.Commit();
}
catch (Exception)
{
tran.Rollback();
throw;
}
}
}