1

このように、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
);
4

1 に答える 1

0

開いている場合は、閉じてください。他の LinqToSql 操作は、このパターンに一致します。

私のコードでは、無条件に接続を開き、最後に接続を閉じます。誰かが開いている接続を私に渡した場合、それは彼らのせいであり、私はたまたま彼らのためにそれを閉じます.

ExecuteReader の直前まで接続を開くのを遅らせることができます。

于 2011-01-28T14:10:29.280 に答える