Modelli MVC ASP.NET, EntityFramework e Automapper

1

Succede in modo che la migliore pratica dell'uso di EntityFramework includa il vantaggio di IQueryable all'interno del blocco using , come:

using (var ctx = new SomeDbContext())
{
  ...(do something with ctx)
}

Se vogliamo disaccoppiare le gomme del database e degli affari (e alla fine della presentazione), ciò comporta la creazione di altri oggetti da oggetti originati dal contesto EF. Automapper è utile qui. Ciò significa che posso fare qualcosa del genere:

using (var ctx = new SomeDbContext())
{
    var dbHeaders = ctx.Headers.ToList();
    var headers = Mapper.Map<List<MyBusinessModel.Headers>>(dbHeaders);
    return headers;
}

Ora sembra che lo pneumatico DB sia abbinato al pneumatico aziendale - vero? List<MyBusinessModel.Headers> è abbastanza usato all'interno del blocco di proprietà di EF. Tuttavia, se volessi farlo ...

List<Headers> dbHeaders = null;
using (var ctx = new SomeDbContext())
{
    dbHeaders = ctx.Headers.ToList();
}
...decoupled!...or?...
var headers = Mapper.Map<List<MyBusinessModel.Headers>>(dbHeaders);
return headers;

... potrebbe funzionare, ma solo se non mappo le entità figlio (le cosiddette proprietà di navigazione). Perché? Quando si usano le uscite di blocco, il contesto è morto e se Automapper ha bisogno di bambini pigri, non si caricheranno e otterrò un'eccezione.

Una posibility sta usando Include() che indica all'EF di caricare avidamente cose. Ma cosa succede se abbiamo un oggetto grafico complesso, dove a volte lavoriamo con una profondità nel grafico, e talvolta con gli altri? Automapper è semplicemente configurato per mappare sempre nello stesso modo. Ciò significa che non importa la profondità, dobbiamo sempre usare aAll include, come

ctx.Headers
   .Include("Items")
   .Include("Items.Details")
   .Include("Items.Details.MoreDetails")
   ...

Sono l'unico a pensare che sia brutto?

Ho deciso di fare un passo più audace e provare quanto segue.

Innanzitutto il pneumatico aziendale ...

List<MyBusinessModel.Headers> headers = null;
SomeDbTireWrapper.MapHeaders((dbHeaders) => {
  headers = Mapper.Map<List<MyBusinessModel.Headers>>(dbHeaders);
});

Quindi lo pneumatico del database ...

public static void MapHeaders(Action<List<Headers>> callbackHeaders)
{
  using (var ctx = new SomeDbContext())
  {
    var items = ctx.Headers.ToList();
    callbackHeaders(items);
  }
}

Sembra funzionare, ma temo che mi colpirà a testa in giù da qualche parte lungo il percorso.

Qualcuno vede il problema con questo approccio?

    
posta OzrenTkalcecKrznaric 09.09.2016 - 23:15
fonte

1 risposta

1

Una soluzione per il problema che stai affrontando è il pattern Application Service Layer . Nel linguaggio di Domain Driven Design questo è chiamato Anti-corruption Layer.

Supponendo che si stia utilizzando un modello di dominio ricco, il livello del servizio applicativo avvolge questo modello e esegue il mapping tra gli oggetti e le operazioni pertinenti all'applicazione e il modello di dominio avanzato supportato dal database. Ad esempio, supponiamo che la tua applicazione sia un portale rivolto al cliente per un sito di e-commerce. E per il gusto di argomentare, diciamo che il tuo modello di dominio sul backend ha una mappatura molto complessa per la creazione di un cliente, ma tu vuoi fornire un metodo semplice per il tuo cliente di fare un ordine, pagarlo e farlo spedire a loro.

Per lo scenario di cui hai bisogno sul front-end, potresti decidere che un modulo di informazioni di ordine semplice sarebbe ottimale per ottenere il cliente in modo efficiente attraverso la procedura di checkout.

Nelfront-end,haiunoggetto(Cliente)cherappresentalalororegistrazione.Sulbackend,staicreandotreoggettiperrappresentarequelcliente.Eccoundiagrammadioggettigrezziperte:

ComevediilServiceServiceLayerèresponsabiledellatraduzionetraidue.Offreall'applicazionefront-endunavisualizzazionesemplificatadelmodellodidominio.IlDMèliberodievolversisenzainfluenzarel'interfacciautenteeilServiceLayergestiscelatraduzionetraidue.

Dettoquesto,hoscopertochelaproiezionedalcontestodirettamentenelmio"Modello di applicazione" è più efficiente (perché richiede meno round trip e meno recupero dei dati rispetto al tentativo di utilizzare un mappatore automatico per lo scopo ... Salva auto mapper per mappature semplici e ripetitive.

Spero che questo aiuti.

    
risposta data 10.09.2016 - 03:23
fonte

Leggi altre domande sui tag