このように、linq-to-sql のコマンドテキストを変更して、強制的に nolock を使用するようにしています...
if (db.Connection.State == System.Data.ConnectionState.Closed)
db.Connection.Open();
var cmd = db.GetCommand(db.Customers.Where(p => p.ID == 1));
cmd.CommandText = cmd.CommandText.Replace("[Customers] AS [t0]", "[Customers] AS [t0] WITH (NOLOCK)");
var results = db.Translate(cmd.ExecuteReader());
これは MVC アプリケーションであるため、datacontext はベース コントローラーにあり、このコードの前、さらに重要なことには後も使用されている可能性があります。このルーチンで接続を閉じる必要がありますか? それともまったくありませんか?それともここで開いた場合のみですか?
アップデート:
現在、より一般的な関数 (DataContext クラス内) を使用して commandtext を変更し、接続がここで開かれている場合は閉じています。そして、open は ExecuteReader に移動されました。これまでのところ、散発的なデッドロックの問題が機能し、軽減されています。結果は最新である必要はありません。
public List<T> GetWithNolock<T>(IQueryable<T> query)
{
// to skip nolock, just...
// return query.ToList();
List<T> results = null;
bool opened = false;
try
{
if (Connection.State == System.Data.ConnectionState.Closed)
{
Connection.Open();
opened = true;
}
using (var cmd = GetCommand(query))
{
cmd.CommandText = Regex.Replace(cmd.CommandText, @"((from|inner join) \[dbo.*as \[t\d+\])", "$1 with (nolock)", RegexOptions.IgnoreCase);
results = Translate<T>(cmd.ExecuteReader()).ToList();
}
}
finally
{
if (opened && Connection.State == System.Data.ConnectionState.Open)
{
Connection.Close();
}
}
return results;
}
過去に、推奨される方法でトランザクションを使用すると、サイトが一晩で接続を使い果たしてしまうことがわかりました。私の知る限り、これは linq-to-sql のバグです。それを回避する方法があるかもしれませんが、私はメイン コードを単純に保つようにしています。私は今「ただ」これをしなければなりません...
var users = GetWithNolock<User>(
Users
.Where(u => my query
);