web-dev-qa-db-ja.com

LINQ-SQLでは、DataContextのラップはusingステートメントです-長所短所

パフォーマンス、メモリ使用量、コーディングの容易さ、正しいことなどの要素の観点から、誰かがLINQ-SQLでDataContextをusingステートメントでラップするかどうかの間で賛否両論について意見を述べることができますか?.

更新ある特定のアプリケーションで、ブロックを使用する際にDataContextをラップせずに、ライブオブジェクトが解放されなかったため、メモリ使用量が増え続けたことがわかりましたGC用。以下の例のように、qオブジェクトのリストへの参照を保持し、qのエンティティにアクセスすると、GC用にリリースされないオブジェクトグラフを作成します。

を使用したDataContext

    using (DBDataContext db = new DBDataContext())
    {
        var q = 
            from x in db.Tables
            where x.Id == someId
            select x;

        return q.toList();
    }

使用せずに存続するDataContext

  DBDataContext db = new DBDataContext()
  var q = 
        from x in db.Tables
        where x.Id == someId
        select x;

    return q.toList(); 

ありがとう。

23
hIpPy

DataContextは、他のものと比較して、作成にコストがかかる可能性があります。ただし、それが完了し、接続をできるだけ早く閉じたい場合は、これにより、キャッシュされた結果がコンテキストから解放されます。何があっても作成していることを忘れないでください。この場合は、ガベージコレクターに、削除する無料のものがもっとあることを通知しているだけです。

DataContextは、短期間の使用オブジェクトとして作成され、それを使用し、作業単位を実行し、実行します...それはまさにあなたが使用して行っていることです。

したがって、利点:

  • より迅速に閉じた接続
  • 廃棄からメモリを解放します(コンテンツ内のキャッシュされたオブジェクト)

欠点-より多くのコード?しかし、それが抑止力になるべきではありません。ここではusingを適切に使用しています。

ここでマイクロソフトの回答を見てください: http://social.msdn.Microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe

using/.Dispose()を使用する必要がある場合の短いバージョン:

短い答え。いいえ、する必要はありませんが、should.。

12
Nick Craver

まあ、それはIDisposableなので、悪い考えではないと思います。 MSFTの人々は、DataContextを可能な限り軽量にして、無謀な放棄で作成できるようにしたと言っています。そのため、おそらくあまり利益を得ていません。

5
James Curran
  1. 初めてDataContextがDBからオブジェクトを取得します。
  2. 次回クエリを実行して同じオブジェクト(同じパラメータ)を取得するとき:プロファイラーにクエリが表示されますが、DataContextのオブジェクトはDBからの新しいオブジェクトに置き換えられません!!

言うまでもなく、すべてのDataContextの背後には、DBに要求しているすべてのオブジェクトのIDマップがあります(これを維持する必要はありません)。

DataContextの全体的な考え方は作業単位 with Optimistic Concurrency。短いトランザクション(1回の送信のみ)に使用し、破棄します。

廃棄を忘れないための最良の方法は、()を使用することです。

5
Vladimir Kojic

私はあなたのデータレイヤーの複雑さに依存します。すべての呼び出しが単純な単一のクエリである場合、各呼び出しは質問の「のように使用」でラップでき、それで問題ありません。

一方、データレイヤーがビジネスレイヤーからの複数の順次呼び出しを予期できる場合は、呼び出しのより大きなシーケンスごとにDataContextを繰り返し作成/破棄することになります。理想的ではありません。

私が行ったことは、データレイヤーオブジェクトをIDisposibleとして作成することです。作成されると(または実際には、メソッドへの最初の呼び出しが行われると)DataContextが作成され、Data Layerオブジェクトが破棄されると、DataContextが閉じて破棄されます。

これがどのように見えるかです:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace PersonnelDL
{
    public class PersonnelData : IDisposable
    {
        #region DataContext management
        /// <summary>
        /// Create common datacontext for all data routines to the DB
        /// </summary>
        private PersonnelDBDataContext _data = null;
        private PersonnelDBDataContext Data
        {
            get
            {
                if (_data == null)
                {
                    _data = new PersonnelDBDataContext(ConfigurationManager.ConnectionStrings["PersonnelDB"].ToString());
                    _data.DeferredLoadingEnabled = false; // no lazy loading
                    //var dlo = new DataLoadOptions(); // dataload options go here
                }
                return _data;
            }
        }

        /// <summary>
        /// close out data context
        /// </summary>
        public void Dispose()
        {
            if (_data != null)
                _data.Dispose();
        }
        #endregion

        #region DL methods
        public Person GetPersonByID(string userid)
        {
            return Data.Persons.FirstOrDefault(p => p.UserID.ToUpper().Equals(userid.ToUpper()));
        }

        public List<Person> GetPersonsByIDlist(List<string> useridlist)
        {
            var ulist = useridlist.Select(u => u.ToUpper().Trim()).ToList();
            return Data.Persons.Where(p => ulist.Contains(p.UserID.ToUpper())).ToList();
        }

        // more methods...
        #endregion
    }
}
3
Mike Jacobs

ある特定のアプリケーションでは、DataContextusingブロックでラップせずに、ライブオブジェクトがGC用にリリースされなかったため、メモリ使用量が増え続けていることを経験しました。以下の例のように、_List<Table>_オブジェクトへの参照を保持し、qのエンティティにアクセスすると、GC用にリリースされないオブジェクトグラフを作成します。

_DBDataContext db = new DBDataContext()
var qs = 
    from x in db.Tables
    where x.Id == someId
    select x;

return qs.toList();

foreach(q in qs)
{
    process(q);
    // cannot dispose datacontext here as the 2nd iteration 
    // will throw datacontext already disposed exception 
    // while accessing the entity of q in process() function
    //db.Dispose();
}

process(Table q)
{
    // access entity of q which uses deferred execution
    // if datacontext is already disposed, then datacontext 
    // already disposed exception is thrown
}
_

この例では、リスト変数Table **内のすべてのqsインスタンスが同じデータコンテキストを共有するであるため、データコンテキストを破棄できません。 Dispose()の後、process(Table q)でエンティティにアクセスすると、データコンテキストで既に破棄された例外がスローされます。

私にとって醜いクルーゲは、foreachループの後にqオブジェクトのすべてのエンティティ参照を削除することでした。もちろん、より良い方法はusingステートメントを使用することです。

私の経験では、usingステートメントを使用すると思います。

1
hIpPy