1

使用されているコンテキストに応じて、異なるグラフ (関連するエンティティ) を持つオブジェクトの読み込みを処理する最善の方法を見つけようとしています。

たとえば、これは私のドメイン オブジェクトのサンプルです。

public class Puzzle
{
    public Id{ get; private set; }
    public string TopicUrl { get; set; }
    public string EndTopic { get; set; }
    public IEnumerable<Solution> Solutions { get; set; }
    public IEnumerable<Vote> Votes { get; set; }
    public int SolutionCount { get; set; }
    public User User { get; set; }
}
public class Solution
{
    public int Id { get; private set; }
    public IEnumerable<Step> Steps { get; set; }
    public int UserId { get; set; }
}  
public class Step
{
    public Id { get; set; }
    public string Url { get; set; }
}
public class Vote
{
    public id Id { get; set; }
    public int UserId { get; set; }
    public int VoteType { get; set; }
}

私が理解しようとしているのは、この情報の使用方法に応じて、この情報を異なる方法でロードする方法です。

たとえば、フロント ページにはすべてのパズルのリストがあります。この時点では、パズルの解決策やそれらの解決策の手順についてはあまり気にしません (これはかなり重くなる可能性があります)。私が欲しいのはパズルだけです。次のようにコントローラーからロードします。

public ActionResult Index(/*  parameters   */)
{
    ...
    var puzzles = _puzzleService.GetPuzzles();
    return View(puzzles);
}

後のパズル ビューでは、現在のユーザーのソリューションのみを気にします。すべてのソリューションとすべてのステップを含むグラフ全体をロードしたくありません。

public ActionResult Display(int puzzleId)
{
   var puzzle = _accountService.GetPuzzleById(puzzleId);
   //I want to be able to access my solutions, steps, and votes. just for the current user.
}

IPuzzleService 内では、メソッドは次のようになります。

public IEnumerable<Puzzle> GetPuzzles()
{
    using(_repository.OpenSession())
    {
        _repository.All<Puzzle>().ToList();
    }
}
public Puzzle GetPuzzleById(int puzzleId)
{
    using(_repository.OpenSession())
    {
        _repository.All<Puzzle>().Where(x => x.Id == puzzleId).SingleOrDefault();
    }
}

私のセッションは各作業単位の直後に破棄されるため、遅延読み込みは実際には機能しません。私のコントローラーにはリポジトリの概念がないため、セッション状態を管理せず、ビューがレンダリングされるまで保持できません。

ここで使用する正しいパターンは何かを理解しようとしています。サービスにさまざまなオーバーロードがありますGetPuzzleWithSolutionsAndVotesか?GetPuzzlesForDisplayViewGetPuzzlesForListView

私は理にかなっていますか?私はベースから離れていますか?助けてください。

4

2 に答える 2

2

遅延読み込みを使用できない同様のケースがありました。

1 つまたは 2 つのケースだけが必要な場合は、提案する最も簡単な方法として、別の GetPuzleWithXYZ() メソッドを作成します。

流暢なインターフェイスを備えた小さなクエリ オブジェクトを作成することもできます。

何かのようなもの...

public interface IPuzzleQuery
{
    IPuzzleLoadWith IdEquals(int id);
}

public interface IPuzzleLoadWith
{
    ISolutionLoadWith WithSolutions();

    IPuzzleLoadWith WithVotes();
}

public interface ISolutionLoadWith
{
    IPuzzleLoadWith AndSteps();
}

public class PuzzleQueryExpressionBuilder : IPuzzleQuery, IPuzzleLoadWith, ISolutionLoadWith
{
    public int Id { get; private set; }
    public bool LoadSolutions { get; private set; }
    public bool LoadVotes { get; private set; }
    public bool LoadSteps { get; private set; }

    public IPuzzleLoadWith IdEquals(int id)
    { 
        Id = id;
        return this;    
    }

    public ISolutionLoadWith WithSolutions()
    {
        LoadSolutions = true;
        return this;
    }

    public IPuzzleLoadWith WithVotes()
    {
        LoadVotes = true;
        return this;
    }

    public IPuzzleLoadWith AndSteps()
    {
        LoadSteps = true;
        return this;
    }
}

次に、Repository Get() メソッドで式ビルダーをインスタンス化し、それを呼び出し元に渡すことができます

public Puzzle Get(Action<IPuzzleQuery> expression)
{
    var criteria = new PuzzleQueryExpressionBuilder();

    expression(criteria);

    var query = _repository.All<Puzzle>().Where(x => x.Id == criteria.Id)

    if(criteria.LoadSolutions) ....

    if(criteria.LoadSteps) ....

    if(criteria.LoadVotes) ....

    ...
    ... 

    return query.FirstOrDefault();
}

典型的な呼び出しは次のようになります...

Puzzle myPuzzle = Repository.Get(where => where.IdEquals(101).WithSolutions());

Puzzle myPuzzle = Repository.Get(where => where.IdEquals(101).WithSolutions().AndSteps());

Puzzle myPuzzle = Repository.Get(where => where.IdEquals(101).WithVotes().WithSolutions());

少し手を加える必要がありますが、基本的な考え方はわかります。

于 2009-08-19T23:02:20.607 に答える
0

あなたのサービスがビューについての知識を持っているべきではないと思います。要件は変更される可能性があるため、それらの名前をビュー名に結び付けないでください。

GetPuzzles() を呼び出すときは、ルート パズルのみをロードする必要があり、GetPuzzleById(int id) は関連付けを熱心にロードできます。

たとえば、条件 API では次のようになります。.SetFetchMode("Solutions", NHibernate.FetchMode.Join)

遅延ロードができない理由がわかりません。nHibernate を使用している場合、プロパティにアクセスするとプロキシがデータベースに戻ります。コントローラーは、必要なすべてのデータを取得する必要があります。ロードされていないプロキシをビューに渡すべきではありません。ビューは、データをロードできない場合を処理する必要があります。

そのため、必要な特定のデータをコントローラーにロードさせる必要があります。ユーザーに対してのみロードするには、次のようにインターフェイスを変更します。GetPuzzle(puzzleId,user)

この方法では、1 人のユーザーのデータを熱心に読み込むことができます。

于 2009-06-22T15:25:56.530 に答える