2

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

    private IRepository _repository;

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

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

これで、データベース呼び出しはリポジトリ内で処理され、リポジトリはServiceクラスから_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に対して以前のクエリを実行してはならないためです。そして、私のリポジトリはすべてのメソッドでデータコンテキストを再利用するため、これはまったく機能しません。私は2つのことを試みてきました。1つは、usingステートメントを使用して、すべてのメソッド内でデータコンテキストを再作成し、データコンテキストが毎回更新されるようにすることです。しかし、リポジトリから結果をモデルにフェッチし直したときに問題が発生し、usingステートメントが終了すると、スコープがリポジトリパターン内で実行されます。つまり、結果を.Count()や。で使用することはできません。データを提供したdatacontextが終了したため、ToList()。また、リポジトリ全体で同じデータコンテキストを使用する別のソリューションを試しました。ただし、dataloadoptionsを使用する各メソッドで新しいインスタンスを作成します。これは非常に汚い感じがしました;)では、リポジトリパターンでDataLoadOptionsを使用する方法について誰かが私に提案を与えることができますか?今説明した問題を避けてください。または、dataloadoptionsを使用して、別の方法を選択するべきではありませんか?ちなみに、DataLoadOptionsを使用する理由は、関連するテーブルからいくつかのデータを取得したいからです。

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

読んでくれてありがとう、そして私の質問に対するいくつかの答えがあることを願っています;)事前にどうもありがとう。さらに詳しい情報が必要な場合は、お問い合わせください。

4

1 に答える 1

0

私は決して専門家ではありませんDataLoadOptionsが、あなたの質問と私がそれについて読んだことから、あなたは熱心な読み込みのためにそれを使用する必要があるようです。これに関連して:

「dataloadoptionsを使用する場合、新しいdataloadoptionsが適用される前に、datacontextに対して以前のクエリを実行してはならないためです。」

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

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

あなたが述べたように、これはメソッドが戻った後、列挙にプリロードされていないオブジェクトにアクセスできなくなります。ただし、クエリをすでに実行して、、、、またはその他の具象に変換しているList場合はCollection、またはメソッドにアクセスする必要はありません。代わりに、またはプロパティを使用できます。ArrayIEnumerableCount()ToList() Array.LengthList.CountCollection.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();
}

確かに、Membersテーブルに多くの行がある場合、これは最適ではない可能性があります。その場合、2つのクエリを実行する必要があります。1つはカウントし、もう1つは行を選択します。これは、次の2つのコンテキストを開くことで実現できます。

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
    }
}
于 2012-04-09T22:17:42.170 に答える