前回のダーティ リードとその解決方法 その 1 では SqlCommand クラスを利用したコードを示しましたが、
今回は ADO.NET Entity Framework を利用したコードを示します。
ただし、特に説明する部分はないので、ステップ 2 (Read Committed) の場合のみ示します。
なお、下記のコードを記述する前に、ロスト アップデートとその解決方法 その 3 と同様に
Visual Studio で ADO.NET Entity Data Model を作成しておきます。
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
namespace DirtyRead
{
class Program
{
private static readonly TransactionOptions transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
private static int hasStockCount;
static void Main(string[] args)
{
// 更新と読み取りを並列に実行します。
Parallel.Invoke(
() =>
{
for (int i = 0; i < 200; i++)
{
UpdateUnitsInStock();
}
},
() =>
{
for (int i = 0; i < 100; i++)
{
SelectUnitsInStock();
}
}
);
}
/// <summary>
/// Northwind データベースの Products テーブルの UnitsInStock の値を更新してロールバックします。
/// </summary>
private static void UpdateUnitsInStock()
{
using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
using (var context = new NorthwindEntities())
{
// 在庫個数を更新します。
Product product = context.Products.Single(p => p.ProductID == 1);
product.UnitsInStock = 1;
context.SaveChanges();
// TransactionScope.Complete メソッドを呼び出さないのでロールバックされます。
}
}
/// <summary>
/// Northwind データベースの Products テーブルの UnitsInStock の値を読み取ります。
/// </summary>
private static void SelectUnitsInStock()
{
using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
using (var context = new NorthwindEntities())
{
// 在庫個数を読み取ります。
Product product = context.Products.Single(p => p.ProductID == 1);
bool hasStock = product.UnitsInStock > 0;
if (hasStock)
{
hasStockCount++;
Console.WriteLine("在庫あり ({0} 回目)", hasStockCount);
}
else
{
Console.WriteLine("在庫なし");
}
}
}
}
}
バージョン情報
.NET Framework 4
SQL Server 2008, 2008 R2