Windows Azure SQL DBでEntity Frameworkを使うときの注意点です。
リトライの組み込み
以下のクラスを作ってEntity Frameworkを含むプロジェクトに置いておきます。
自分でトランザクションを作成せず、Entity Frameworkにトランザクション管理をまかせる場合はこれだけでOKです。
public class SampleConfiguration : DbConfiguration
{
public SampleConfiguration()
{
SetExecutionStrategy(
"System.Data.SqlClient",
() => new SqlAzureExecutionStrategy(5, TimeSpan.FromSeconds(30))
);
}
}
自分でトランザクションを作成する
リトライを有効にして、かつ、自分でトランザクションを作成したい場合は工夫が必要になります。
前述のSampleConfigurationを使ってリトライを組み込んだとき、以下のコードはサポートされません。
2回目のSaveChanges()が失敗したときに1回目のSaveChanges()もリトライしないといけないことを
EntityFrameworkが認識できないからです。
// サポートされないコード
using (var context = new SampleContext())
using (var tran = context.Database.BeginTransaction())
{
context.Samples.Add(new Sample());
context.SaveChanges();
context.Samples.Add(new Sample());
context.SaveChanges();
tran.Commit();
}
対策方法は、まず、SampleConfigurationクラスを以下のように修正します。
これでSampleConfiguration.SuspendExecutionStrategyをtrueにすると
SaveChanges()などでEntity FrameworkがDefaultExecutionStorategyを使うようになります。
public class SampleConfiguration : DbConfiguration
{
public SampleConfiguration()
{
SetExecutionStrategy(
"System.Data.SqlClient",
() => SuspendExecutionStrategy ?
(IDbExecutionStrategy) new DefaultExecutionStrategy() :
new SqlAzureExecutionStrategy());
}
public static bool SuspendExecutionStrategy
{
get
{
return (bool?) CallContext.LogicalGetData(
"SuspendExecutionStrategy") ?? false;
}
set
{
CallContext.LogicalSetData("SuspendExecutionStrategy", value);
}
}
}
SaveChanges()でのリトライ処理に無効にしたうえで、
SqlAzureExecutionStrategyを手動で使ってトランザクション全体がリトライ対象になるようにします。
var executionStrategy = new SqlAzureExecutionStrategy();
SampleConfiguration.SuspendExecutionStrategy = true;
executionStrategy.Execute(
() =>
{
using (var context = new SampleContext())
using (var tran = context.Database.BeginTransaction())
{
context.Samples.Add(new Sample());
context.SaveChanges();
context.Samples.Add(new Sample());
context.SaveChanges();
tran.Commit();
}
});
SampleConfiguration.SuspendExecutionStrategy = false;