Question

J'essaie de déterminer le meilleur moyen de gérer le chargement d'objets avec différents graphes (entités liées) en fonction du contexte d'utilisation.

Par exemple, voici un exemple d'objet de domaine:

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; }
}

Ce que j'essaie de comprendre, c'est comment charger cette information différemment en fonction de la manière dont je l'utilise.

Par exemple, sur la page d'accueil, j'ai une liste de tous les puzzles. À ce stade, je ne me soucie pas vraiment des solutions pour le casse-tête ou des étapes de ces solutions (qui peuvent devenir assez lourdes). Tout ce que je veux, ce sont les énigmes. Je les chargerais depuis mon contrôleur comme ceci:

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

Plus tard, pour la vue puzzle, je ne me soucie plus que des solutions pour l'utilisateur actuel. Je ne veux pas charger le graphique entier avec toutes les solutions et toutes les étapes.

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.
}

Dans mon IPuzzleService, mes méthodes ressemblent à ceci:

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();
    }
}

Le chargement paresseux ne fonctionne pas vraiment dans le monde réel, car ma session est mise au rebut juste après chaque unité de travail. Mes contrôleurs n’ont aucun concept de référentiel et ne gèrent donc pas l’état de la session. Ils ne peuvent pas le conserver tant que la vue n’a pas été rendue.

J'essaie de comprendre quel est le bon modèle à utiliser ici. Dois-je différentes surcharges sur mon service, telles que GetPuzzleWithSolutionsAndVotes ou une vue spécifique, telle que GetPuzzlesForDisplayView et GetPuzzlesForListView ?

Est-ce que j'ai un sens? Suis-je bien en dehors de la base? S'il vous plaît aider.

Était-ce utile?

La solution

J'ai eu un cas similaire où je ne pouvais pas utiliser le chargement paresseux.

Si vous n'avez besoin que d'un ou deux cas, la chose la plus simple à suggérer est de créer des méthodes GetPuzleWithXYZ () distinctes.

Vous pouvez également créer un petit objet de requête avec une interface fluide.

Quelque chose comme ...

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;
    }
}

alors votre méthode Get () de référentiel peut instancier le générateur d'expression et le transmettre à l'appelant

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();
}

et les appels typiques ressemblent à ...

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());

Cela nécessite un peu de travail, mais vous pouvez voir l’idée de base.

Autres conseils

Je ne pense pas que votre service devrait avoir une quelconque connaissance des vues. Vos besoins pourraient changer, alors ne liez pas leurs noms pour afficher les noms.

Lorsque vous appelez GetPuzzles (), vous ne devez charger que le puzzle racine, et GetPuzzleById (int id) peut charger les associations avec impatience.

Par exemple, dans l'API de critères: .SetFetchMode ("Solutions", NHibernate.FetchMode.Join)

Je ne comprends pas pourquoi vous ne pouvez pas charger paresseux. Si vous utilisez nHibernate, le proxy reviendra à la base de données pour vous lorsque vous accéderez à la propriété. Votre contrôleur devrait obtenir toutes les données dont vous avez besoin. Vous ne devez pas transmettre un proxy non chargé à votre vue, celle-ci devant gérer le cas où elle ne peut pas charger les données.

Donc, vous devriez demander au contrôleur de charger les données spécifiques dont vous avez besoin, pour ne charger que pour un utilisateur, je modifierais l'interface de la manière suivante: GetPuzzle (puzzleId, utilisateur)

Dans cette méthode, vous pouvez simplement charger les données pour le seul utilisateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top