Domanda

Sto usando ASP.NET MVC 3, con Raven DB come archivio dati di supporto. Ho una serie di modelli, che sono interessato a trasformare in ViewModel. Per fare questo, sto sfruttando automapper a prendersi cura del lavoro sporco di mappare ogni struttura al corrispondente nel ViewModel. diciamo di Let che ho un modello in questo modo:

public class FooModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AlphaId { get; set; }
    public int BetaId { get; set; }
}

E poi diciamo che voglio trasformarlo in un ViewModel in questo modo:

public class FooViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AlphaId { get; set; }
    public Alpha Alpha { get; set; }
    public int BetaId { get; set; }
    public Beta Beta { get; set; }
}

La mia mappa è quindi impostato in questo modo all'avvio app:

Mapper.CreateMap<Foo, FooViewModel>();

Poi, nel controller sto eseguendo la mappa come:

public ActionResult FooDetails(string id)
{
    using(var session = this.documentStore.OpenSession())
    {
        var fooInstance = session.Load<Foo>(id);
        var fooViewModel = Mapper.Map<FooViewModel>(fooInstance);
        return this.View(fooViewModel);
    }
}

Il problema è che, come si può vedere sopra, l'entità che esce dal repository ha 2 proprietà che sono le chiavi di altri oggetti, di tipo alfa e beta. Mi interessa idratante Alfa e Beta in base ai tasti AlphaId e BetaId.

In un primo momento ho pensato di sfruttare le funzionalità di conversione personalizzati di automapper, ma non credo che funzionerà, dato che ci sarebbe bisogno di una sessione di dati da iniettare nella mappatura (per richiamare l'archivio dati per recuperare l'Alpha o oggetto beta).

L'altra opzione è quella di fare proprio tutto il lavoro in azione di controllo, ma che diventa rapidamente ingombrante (non nel particolare esempio dato, ma questo è solo un esempio per illustrare il punto).

Dove dovrebbe l'idratazione di Alfa e Beta si svolgono, e che cosa è un modello di buona qui?

È stato utile?

Soluzione

E forse non è l'ideale, ma potrebbe non solo creare le mappe per i due riferimenti e mapparli dopo il fatto. Hai ancora chiamarli separatamente, ma si sta lasciando automapper fare la mappatura pesante, piuttosto che riempire il controller con le proprie mappe.

public ActionResult FooDetails(string id)
{
    using(var session = this.documentStore.OpenSession())
    {
        var foo = session.Load<Foo>(id).Include(....);
        var alpha = session.Load<Alpha>(foo.AlphaId);
        var beta = session.Load<Beta>(foo.BetaId);

        // null checks

        var fooViewModel = Mapper.Map<FooViewModel>(foo);
        fooViewModel.Alpha = Mapper.Map<AlphaViewModel>(alpha);
        fooViewModel.Beta = Mapper.Map<BetaViewModel>(beta);

        return View(fooViewModel);
    }
}  

Non ho usato automapper più di tanto, ma forse si può passare oggetti figlio tramite la funzione Map (per alimentare le catene ForMember su CreateMap)? Forse AfterMap suggerimento lavoro potrebbe di Alexandre, ma non vedo come si sarebbe idratare i bambini '' a cui fa riferimento, senza creare la mappa all'interno della azione di controllo (ma allora si può anche semplicemente usare ForMember e la sessione Raven direttamente e hanno una sola Mapper.Map).

Aggiunta - La documentazione automapper suggerisce un metodo simile per / bambino nested mappe - https://github.com/AutoMapper/AutoMapper/wiki/Nested-mappings . Anche se è più simile a un riferimento a un oggetto, piuttosto che una situazione di riferimento oggetto id.

Non posso commentare su altre risposte ancora, ma per quanto riguarda la risposta di Pavel - in realtà non utilizzano Raven in questo modo, non v'è alcuna O / R mapping (diverso da quello JSON interna -> oggetto) o dati livello di accesso, è sufficiente utilizzare la sessione Raven direttamente (magari attraverso un servizio, ma non c'è certamente bisogno di un repository o simili). Per quanto riguarda i riferimenti, di byte ha diritto e come ha commentato uno degli altri risposte, l'approccio migliore è quello di memorizzare un riferimento id e utilizzare un Raven includere -. È lo stesso risultato e usa ancora solo una richiesta

Altri suggerimenti

Sono d'accordo con la persona lì, ma se non è possibile espandere il modello, è sempre possibile definire la mappatura con AfterMap in questo modo:

Mapper.CreateMap<Foo, FooViewModel>()
.AfterMap(MapAlphaBetaFromFooToFooViewModel);


public void MapAlphaBetaFromFooToFooViewModel(Foo foo, FooViewModel fooViewModel)
{
// Here the code for loading and mapping you objects
}

in questo modo, quando farete la mappatura, Automapper verrà eseguito automaticamente il metodo dopo la mappatura di base è fatto.

Un'ottimizzazione che si possa fare è di caricare il documento correlato in una volta sola da RavenDB e non fare la chiamata separato per caricare ogni documento correlato. documentazione See RavenDB qui .

Non riesco a pensare a nessun altro modo per mappare i soggetti diversi che farlo nel controller stesso, come avete dimostrato.

Si dovrebbe preoccuparsi la vostra architettura al primo posto. Caricamento dei dati da DB è una responsabilità di strato di accesso ai dati, e non dovrebbe sapere come è organizzato l'interfaccia utente.

Credo che, l'approccio migliore è la seguente distribuzione delle responsabilità:

    Strato
  1. Accesso ai dati ha un modello POCO-based in cui entità hanno riferimenti a vicenda invece di identificatori. Questo modello è esposto a strati superiori (viewmodel per esempio).
  2. La DAL ha un unico metodo che carica tutti i dati necessari per l'azione destinato. Nel tuo caso si dovrebbe caricare entrambe le entità Foo, Alpha, Beta. Dal momento che questo accade in un metodo di DAL, probabilmente può fare questo in una singola query db. Anche se il trucco principale è che altri strati non importa come funziona.
  3. Nel vostro controller che quindi utilizzare automapper per appiattire l'oggetto FooModel in FooViewModel, che è una delle caratteristiche Automapper.

I punti chiave sono:

  1. Solo DAL sa come carica i dati. Se necessario, è possibile modificare come si desidera, senza dover modificare il codice automapper-correlato.
  2. automapper mappe dati solo da una struttura all'altra e non influenza la strategia di caricamento dei dati.

Detto questo, vorrei solo modificare il tuo FooModel:

public class FooModel
{
  public int Id { get; set; }
  public string Name { get; set; }
  public Alpha Alpha { get; set; }
  public Beta Beta { get; set; }
}

e il codice che lo carica dal DB.

Tuttavia, si può richiedere l'originale FooModel-come la struttura, ad esempio, definire un object-relational mapping a quella struttura semplice. Ma ancora è solo fino al DAL.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top