Я изменяю командный текст 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), чтобы изменить командный текст и закрыть соединение, если оно было открыто здесь. И открытие было перемещено вниз в 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
);