2012-04-09 12 views
2

MVC3を実行しているプロジェクトが少しあります。 LINQを使用してデータベースからデータをフェッチします。 私は、MVC3に付属している前例と同じアーキテクチャ設計でプロジェクトを構築しました。 このようなプロジェクトでは、アプリケーションが分割され、このトピックではModel.csファイルに焦点を当てたいと思います。私は現在、各コントローラのための1つを持っているので、例として、私はHighscoreController.csとHighscoreModels.csを持っています。モデルクラスでは、datacontextへの参照を持つServiceクラスと、このdatacontextを使用してデータベースにクエリを行ういくつかのメソッドを定義します。 これらのメソッドのいくつかが同じクエリを実行しているという問題が発生したため、データベースへのアクセスの中心点を作って、リポジトリパターンを実装すると思っていました。MVC、リポジトリパターンとDataLoadOptions

private IRepository _repository; 

    public HighscoreService() 
     : this(new Repository()) 
    { } 

    public HighscoreService(IRepository repository) 
    { 
     _repository = repository; 
    } 

今すぐデータベース呼び出しがリポジトリ内で処理され、リポジトリがサービスクラスから使用されている: は、だからではなく、サービスクラスでのDataContextを参照したの私は今のようなリポジトリへの参照を持っています_repository参照を介して。私のリポジトリは、このように構築されている

public class Repository : IRepository 
    { 
    private MyDataContext _dataContext; 

    public Repository() 
    { 
     _dataContext = new MyDataContext(); 
    } 

    public Member MemberByName(string memberName) 
    { 
     Member member = CompiledQueries.MemberByName(_dataContext, memberName); 
     return member; 
    } 
    } 

私はこのリポジトリパターンとの組み合わせでDataLoadOptionsを使用しようとすると、私が直面する問題が表示されます。

dataloadoptionsを使用する場合、新しいdataloadoptionsが適用される前にdatacontextで以前のクエリを作成していてはいけません。私のリポジトリはすべてのメソッドでdatacontextを再利用しているため、これは全く機能しません。 私は2つのことを試しています.1つは、usingステートメントを使用して、datacontextが毎回リフレッシュされることを確認するために、すべてのメソッド内でdatacontextを再作成しています。しかし、リポジトリの結果をモデルに戻してスコープがリポジトリパターン内で使い果たされたときに、問題が発生します。これは、usingステートメントが終了すると、結果が使用できないことを意味します。私にデータを提供したdatacontextが終了したので、.Count()または.ToList()また、リポジトリ全体で同じdatacontextを使用する別のソリューションを試しましたが、dataloadoptionsを使用する各メソッドで新しいインスタンスを作成しました。これは非常に汚いと感じました;) 誰も私にリポジトリパターンでDataLoadOptionsを使用する方法の提案をしてもらえますか?私が今説明した問題を避けてください。または、私はdataloadoptionsを使用しないで、それを行う別の方法を選択する必要がありますか?ところで、DataLoadOptionsを使用する理由は、関連するテーブルからデータを取得したいからです。

少しの質問として:上記のコード例では、CompiledQueriesを独自の.csファイル内に配置していることがわかります。これは悪いデザインですか?コンパイルされたクエリをMVCアプリケーションに配置するためのガイドラインはありますか?

ご質問ありがとうございます。読んでいただきありがとうございます。より多くの情報が必要な場合は、尋ねてください。

+0

私はエキスパートではありませんが、私はあなたのデータコンテキストを「要求範囲」に保つというアイデアは役に立ちます。このように、HTTP要求ごとに新しいコンテキストが作成されるため、いくつかの問題が取り除かれる可能性があります。 NinjectのようなIoCコンテナはこれを助けることができます。 Entity Frameworkを参照している間、次の投稿が役に立ちます:http://buildstarted.com/2010/08/24/dependency-injection-with-ninject-moq-and-unit-testing/ – ngm

+0

リポジトリを注入してセットアップperWebRequestとしてのライフスタイル。無駄な抽象レイヤーを追加する以外は、リポジトリがあなたのために何をしているのかはまだ分かりません。 – CrazyCoderz

答えて

0

私は決してDataLoadOptionsのエキスパートではありませんが、あなたの質問と私がそれについて読んだことから、熱心な読み込みに使用する必要があるようです。

"dataloadoptionsを使用すると、新しいdataloadoptionsが適用される前にdatacontextで以前のクエリを実行していてはいけません。"

..私には、DataLoadOptions(私は個人的にはLINQ to SQLではなくEntity Frameworkを使用しています)の欠点や設計上の欠陥のように思えます。ngmとCrazyCoderzの最初の2つのコメントで提供されているように、HTTPリクエストごとに単一のデータコンテキストを持つことをお勧めしますが、これで問題が解決されるとは思われません。単一のHTTP要求内で単一のデータコンテキストを再利用する場合は、最初のクエリを実行するとすぐに、データコンテキストのDataLoadOptionsを新しい値に設定できないように思えます。

プレゼンターがvslive vegasでプレゼンテーションを見たところで、発表者があなたが挙げたソリューションの1つを提供し、各リポジトリメソッドに新しいデータコンテキストを作成しました。ここで行う必要があるのは、の前にToList()またはToArray()を呼び出すことです。の前に、usingステートメントを終了してメソッドの結果を返します。

前述のとおり、メソッドが返された後、列挙型にプリロードされていないオブジェクトはアクセス不可能になります。あなたが既に持っている場合は、クエリが実行され、ListCollectionArray、または他のいくつかの具体的なIEnumerableに変換し、あなたはもはやCount()またはToList()方法にアクセスする必要はありません。代わりに、Array.LengthまたはList.CountまたはCollection.Countプロパティを使用できます。

他に、各リポジトリメソッドで新しいデータコンテキストを作成するのを止めようとしていますか?意味、リポジトリメソッドを実行した後で、処分されたために取得できないデータコンテキストは何に必要ですか? 、あなたはこれをあなたの最初のクエリのコメント

返信を行うことができますか?

public Member GetSomeRandomMember() 
{ 
    Member[] members = null; 
    using (var context = new MyDataContext()) 
    { 
     // execute the query to get the whole table 
     members = context.Members.ToArray(); 
    } 

    // do not need to query again 
    var totalRows = members.Length; 
    var skipThisMany = PerformRandomNumberComputation(totalRows); 
    return members.Skip(skipThisMany).FirstOrDefault(); 
} 

メンバーテーブルに大量の行がある場合は、最適ではない可能性があります。その場合、2つのクエリを実行したいと思います.1つは数え、もう1つは行を選択します。あなたのコメントの後半部分について

public Member GetSomeRandomMember() 
{ 
    using (var context1 = new MyDataContext()) 
     var totalRows = context1.Members.Count(); 

    var skipThisMany = PerformRandomNumberComputation(totalRows); 

    Member member = null; 
    using (var context2 = new MyDataContext()) 
     member = context2.Members.Skip(skipThisMany).FirstOrDefault(); 

    return member; 
} 

、私は私はあなたが話しているものを手に入れるかわからない:あなたは2つのコンテキストを開いていることを達成できます。データのフェッチとそれに作る変更はすべて、とにかく単一のコンテキストで単一の操作で来る必要があります:

public void SaveMember(int id, string email, bool isSuspended) 
{ 
    using (var context = new MyDataContext()) 
    { 
     var member = context.Members.Single(m => m.Id == id); 
     member.Email = email; 
     member.IsSuspended = isSuspended; 
     context.SaveChanges(); // or whatever the linq to sql equivalent is 
    } 
} 

をリポジトリメソッドにエンティティ全体を渡したい場合は、あなたはまだそれを照会します

public void SaveMember(Member member) 
{ 
    var memberDto = member; 
    using (var context = new MyDataContext()) 
    { 
     member = context.Members.Single(m => m.Id == memberDto.Id); 
     member.Email = memberDto.Email; 
     member.IsSuspended = memberDto.IsSuspended; 
     context.SaveChanges(); // or whatever the linq to sql equivalent is 
    } 
} 
+0

お返事ありがとうございます。今、私はテーブル全体をロードしています。次にカウントを行い、そのカウントに基づいて乱数を生成します。これは.Skip(randomNumber).FirstOrDefault()で同じロード結果に使用されます。だから私が遅れて読み込むことができないなら、それを2つのクエリに分割しなければならないでしょう.1つはカウントを得るため、もう1つは実際の行を取得することです。コンテキストを終了すると、データを取得して変更を加え、コンテキストを終了すると以前に取得したロード結果に変更を正しく挿入できないため、データを取り戻すことができます。 – emin

+0

あなたの答えと華麗なコード例をお寄せいただきありがとうございます。私は最初の部分について何を考えているのか分かりません。多くのデータコンテキストを開いています。なぜなら、パフォーマンスの重視がそれほどわからないからです。私は少しきれいだったいくつかの魔法の解決策を望んでいたと思う;)2番目の部分は非常に意味があり、私は代わりにそのようにすることを確認します。ありがとう – emin

+0

@emin、2つのデータコンテキストを開いて廃棄することは理想的ではありませんが、これは1つのオプションと他のオプションのパフォーマンスを比較検討する必要があるケースです。最初のコードスニペットを実行することによって、本質的にdb上で 'SELECT * FROM Members'を実行します。これにより、dbはすべての行をメモリに戻します。メンバーテーブルに数千または数百万の行がある場合、これは遅くて高価になります。 2番目のオプションは 'SELECT COUNT(*)FROM Members'、次に' SELECT * FROM Members WHERE ID = @ ID'です。テーブルにたくさんの行があると、よりパフォーマンスが向上します。 – danludwig

関連する問題