문제

사용되는 컨텍스트에 따라 서로 다른 그래프(관련 엔터티)가 있는 개체 로드를 처리하는 가장 좋은 방법을 찾으려고 노력 중입니다.

예를 들어 다음은 내 도메인 개체의 샘플입니다.

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 또는 더 많은 보기 특정 GetPuzzlesForDisplayView 그리고 GetPuzzlesForListView?

내가 이해하고 있는 걸까?내가 기지에서 멀리 떨어져 있는 걸까?도와주세요.

도움이 되었습니까?

해결책

지연 로딩을 사용할 수 없는 비슷한 경우가 있었습니다.

한두 가지 사례만 필요한 경우 제안한 가장 쉬운 방법은 별도의 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());

약간의 작업이 필요하지만 기본 아이디어를 볼 수 있습니다.

다른 팁

귀하의 서비스에는 뷰에 대한 지식이 없어야 한다고 생각합니다.요구 사항이 변경될 수 있으므로 해당 이름을 보기 이름에 연결하지 마십시오.

GetPuzzles()를 호출할 때 루트 퍼즐만 로드해야 하며 GetPuzzleById(int id)는 연관을 즉시 로드할 수 있습니다.

예를 들어 기준 API에서는 다음과 같습니다. .SetFetchMode("Solutions", NHibernate.FetchMode.Join)

왜 게으른 로드를 할 수 없는지 이해가 되지 않습니다.nHibernate를 사용하는 경우 속성에 액세스하면 프록시가 데이터베이스로 돌아갑니다.컨트롤러는 필요한 모든 데이터를 얻어야 합니다.로드되지 않은 프록시를 뷰에 전달하면 안 되며, 뷰는 데이터를 로드할 수 없는 경우를 처리해야 합니다.

따라서 컨트롤러가 필요한 특정 데이터 부분을 로드하도록 해야 하며, 사용자에 대해서만 로드하려면 인터페이스를 다음과 같이 변경하겠습니다. GetPuzzle(puzzleId,user)

이 방법에서는 한 사용자의 데이터를 즉시 로드할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top