ロスト アップデートとその解決方法 その 1 では SqlCommand クラスを利用したコードを示しましたが、
今回は ADO.NET Entity Framework を利用したコードを示します。
ただし、ステップ 3 (Read Committed & UPDLOCK) の場合のみ示します。
Entity Framework では基本的に LINQ to Entities でクエリを記述しますが、更新ロックを取得するための構文は存在しません。
ObjectContext.ExecuteStoreQuery メソッドにより、データベースに依存する任意の SELECT 文を実行できます。
なお、下記のコードを記述する前に Visual Studio で ADO.NET Entity Data Model を作成しておきます。
名前は NorthwindModel.edmx としておきます。
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
namespace LostUpdate
{
class Program
{
private static readonly TransactionOptions transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
static void Main(string[] args)
{
Parallel.For(0, 100, i => AddUnitsInStock());
}
private static void AddUnitsInStock()
{
try
{
short oldValue, newValue;
using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
using (var context = new NorthwindEntities())
{
// 商品を取得します。
Product product = context.ExecuteStoreQuery<Product>("select * from Products with (updlock) where ProductID = {0}", 1).Single();
context.AttachTo("Products", product);
// 在庫個数を 1 だけ増加させます。
oldValue = product.UnitsInStock.Value;
newValue = (short)(oldValue + 1);
product.UnitsInStock = newValue;
// 商品を更新します。
context.SaveChanges();
// コミットします。
scope.Complete();
}
Console.WriteLine("{0} → {1}", oldValue, newValue);
}
catch (System.Data.DataException ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
注意点
(1) ObjectContext.ExecuteStoreQuery メソッドでパラメーター化クエリを実行する場合、
パラメーター名には順に {0}, {1}, {2}, … または @p0, @p1, @p2, … を使用します。
(2) ObjectContext.ExecuteStoreQuery メソッドを使用した場合、
取得したデータは自動的に ObjectContext にアタッチされないため、ObjectContext.AttachTo メソッドを呼び出します。
標準的な
Product product = context.Products.Single(p => p.ProductID == 1);
などのような場合には呼び出す必要はありません。
(3) UPDATE、INSERT、DELETE などの変更操作を任意の SQL で実行する場合には、
ObjectContext.ExecuteStoreCommand メソッドを使用します。
バージョン情報
.NET Framework 4
SQL Server 2008, 2008 R2
参照
ObjectContext.ExecuteStoreQuery メソッド
ObjectContext.ExecuteStoreCommand メソッド
ストア コマンドの直接実行