Trovare il modello giusto per caricare oggetti con diversi grafici
-
06-07-2019 - |
Domanda
Sto cercando di capire il modo migliore per gestire il caricamento di oggetti con grafici diversi (entità correlate) a seconda del contesto in cui vengono utilizzati.
Ad esempio Ecco un esempio dei miei oggetti dominio:
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; }
}
Quello che sto cercando di capire è come caricare queste informazioni in modo diverso a seconda di come le sto usando.
Ad esempio, in prima pagina ho un elenco di tutti i puzzle. A questo punto non mi interessa davvero le soluzioni per il puzzle o i passaggi in quelle soluzioni (che possono diventare piuttosto pesanti). Tutto quello che voglio sono i puzzle. Vorrei caricarli dal mio controller in questo modo:
public ActionResult Index(/* parameters */)
{
...
var puzzles = _puzzleService.GetPuzzles();
return View(puzzles);
}
In seguito per la vista puzzle ora mi occupo solo delle soluzioni per l'utente corrente. Non voglio caricare l'intero grafico con tutte le soluzioni e tutti i passaggi.
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.
}
All'interno del mio IPuzzleService, i miei metodi si presentano così:
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();
}
}
Il caricamento lento non funziona davvero nel mondo reale, perché la mia sessione viene eliminata subito dopo ogni unità di lavoro. I miei controller non hanno alcun concetto di repository e quindi non gestiscono lo stato della sessione e non possono trattenerlo fino a quando la visualizzazione non viene renderizzata.
Sto cercando di capire quale sia lo schema giusto da usare qui. Ho diversi sovraccarichi sul mio servizio come GetPuzzleWithSolutionsAndVotes
o più visualizzazione specifica come GetPuzzlesForDisplayView
e GetPuzzlesForListView
?
Sto dando un senso? Sono lontano dalla base? Per favore aiutate.
Soluzione
Ho avuto un caso simile in cui non potevo usare il caricamento lento.
Se hai solo bisogno di uno o due casi, allora la cosa più semplice come suggerisci, crea metodi GetPuzleWithXYZ () separati.
Puoi anche creare un piccolo oggetto query con un'interfaccia fluida.
Qualcosa come ...
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;
}
}
quindi il metodo Get () del repository può creare un'istanza del generatore di espressioni e passarlo al chiamante
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();
}
e le chiamate tipiche sembrano ...
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());
ha bisogno di un po 'di lavoro, ma puoi vedere l'idea di base.
Altri suggerimenti
Non credo che il tuo servizio dovrebbe essere a conoscenza delle Viste. I tuoi requisiti potrebbero cambiare, quindi non legare i loro nomi per visualizzarli.
Quando chiami GetPuzzles () devi solo caricare il puzzle di root, e GetPuzzleById (int id) può caricare le associazioni.
Ad esempio nell'API criteri: .SetFetchMode (" Solutions " ;, NHibernate.FetchMode.Join)
Non capisco perché non riesci a caricare lentamente. Se si utilizza nHibernate, il proxy tornerà al database automaticamente quando si accede alla proprietà. Il controller dovrebbe ottenere tutti i dati necessari. Non è necessario passare un proxy non caricato alla vista, quindi la vista deve gestire il caso in cui non è possibile caricare i dati.
Quindi dovresti fare in modo che il controller carichi i dati specifici di cui hai bisogno, per caricare solo per un utente, cambierei l'interfaccia in modo che: GetPuzzle(puzzleId,user)
In questo metodo puoi semplicemente caricare i dati per un solo utente.