2014-10-15 15 views
7

Di chi è la responsabilità di popolare i valori in un'architettura ASP MVC 5 (C#, EF), ad es. se abbiamo PurchaseRecordsViewModel , PurchaseRecords Domain Model , PurchaseControllerChi popola ViewModel in ASP MVC 5

  • Fa il codice per popolare i dati (tempi, costi, ecc) fare da ViewModel, proprio di un proprio ViewModel andare in PurchaseRecordsViewModel?

  • O, fa il codice andare nel metodo d'azione dei PurchaseController

risposta

6

Espansione della risposta di Tommy, ecco un codice per accompagnare la sua descrizione.

//Controller 

public ActionResult Index() 
{ 
    List<OrderViewModel>() model = new List<OrderViewModel>(); 
    model = new ServiceClass().GetOrders(); 

    return View(model); 
} 

//here is your Service Class, this layer transfers the Domain Model into your ViewModel 
public List<OrderViewModel> GetOrders() 
{ 
    List<OrderDomain> model = new List<OrderDomain>(); 

    model = new DataAccess().GetOrders(); 

    List<OrderViewModel> viewModel = new List<OrderViewModel>(); 

    foreach (var order in model) 
    { 
     OrderViewModel vm = new OrderViewModel(); 
     vm.OrderId = order.OrderId; 
     vm.OrderName = order.OrderName; 

     viewModel.Add(vm); 
    }  

    return viewModel;   
} 

//some DataAccess class, this class is used for database access 

Public List<OrderDomain> GetOrders() 
{ 
    List<OrderDomain> model = new List<OrderDomain>(); 

     using (var context = new MyEntities()) 
     { 
      model = (from x in context.Order 
        select new OrderDomain 
        { 
        OrderId = x.OrderId, 
        OrderName = x.OrderName 
        }).ToList();      
     } 
    return model; 
} 
+0

ben spiegato! Nel popolo vuoi dire qualcosa come DBContext . Populate() - La mia domanda più profonda è ciò che accade con le relazioni tra le tabelle, che sta gestendo tale responsabilità, per es. come in uno scenario di griglia dettagli master – aggie

+0

No 'Populate()' è solo il nome del metodo che sto chiamando. La tua classe DataAccess gestirà le operazioni del database. Inverterò l'ordine in modo che il codice venga eseguito in sequenza mentre leggi, iniziando dal controller. – CSharper

+1

@CSharper - Sto cercando di capire il giusto approccio per il mio progetto e ho trovato questo post e la tua risposta ... Ho un dubbio: in genere manteniamo ViewModel in Web Project, mentre Service in un progetto Business Layer separato, in questo caso, per popolare viewmodel nel livello di servizio, devo aggiungere un riferimento al progetto web. Non è un po 'strano? –

11

Visualizza i modelli sono in genere solo collezioni muti di proprietà. La compilazione di un modello di visualizzazione generalmente si basa sul livello di servizio o, se non ne hai uno, sul metodo di azione.

Pensa ai ruoli in questo modo.

  • Un modello di dominio è un'associazione diretta a una tabella di database.
  • Un modello di vista è una raccolta di proprietà necessarie per visualizzare una vista.
  • Un livello di servizio ottiene/utilizza uno o più modelli di dominio e popola un modello di visualizzazione.
  • Un livello di servizio può anche prendere un modello di vista e creare/aggiornare uno o più modelli di dominio
  • Un metodo di azione del controller è la colla tra i due. Chiama un livello di servizio per ottenere (GET) un modello di vista e passarlo a una vista. Questi metodi di azione accettano (POST) anche un modello di vista e lo passano al livello di servizio per fare tutto il necessario.

Un'altra domanda in genere posta è perché non è possibile utilizzare i modelli di dominio per una visualizzazione? È possibile, ma in genere ti imbatti in cose come, che richiedono dati da più di un modello di dominio, non necessitano di tutte le proprietà presenti nel modello di dominio e, infine, ora dovresti preoccuparti delle proprietà che vengono aggiornate sul modello di dominio che non intendeva

+0

Anche dalla tua risposta, il livello di servizio odora di livello extra. Ad eccezione delle app aziendali, il livello di servizio è eccessivo. – DarthVader

+1

@DarthVader: in realtà, la maggior parte delle app MVC che ho mai visto utilizzano un livello di servizio (livello aziendale). Indipendentemente da ciò, sto usando il livello "servizio" qui come esempio per mostrare come usi e popola il dominio e vedi i modelli.Hai ragione, non importa dove vengono generati i tuoi modelli di visualizzazione. Tuttavia, molti esempi qui su SO e altrove (http://codebetter.com/iancooper/2008/12/03/the-fat-controller/) mettono in guardia contro i controller "grassi". – Tommy

+0

Sono d'accordo con Tommy, i controller skinny sono decisamente migliori di quelli grassi – CSharper

3

Idealmente, il tuo modello di visualizzazione dovrebbe essere inconsapevole del tuo modello di dominio, quindi direi che inserisci la logica della popolazione nel controller, magari racchiusa in una sorta di classe di utilità di mapping/popolazione.

Ma ricorda, quando si tratta di domande su dove mettere una certa logica, le preferenze personali vanno molto lontano.

+0

Ok, quindi questa è la discrezione utente/devleoper !! – aggie

6

Idealmente, dovrebbe PurchaseRecordViewModel popolarsi ottenendo PurchaseRecordsDomainModel. Dovrebbe contenere una semplice mappatura delle proprietà e possibilmente una formattazione dell'output che verrà utilizzato nella visualizzazione.

PurchaseRecordsViewModel

public class PurchaseRecordsViewModel 
{ 
    public IEnumerable<PurchaseRecordViewModel> PurchaseRecords {get;set;} 
} 

PurchaseRecordViewModel

public class PurchaseRecordViewModel 
{ 
    public DateTime Date {get;set;} 
    public decimal Cost {get;set;} 
    // .... some other properties 
    public PurchaseRecordsViewModel(PurchaseRecordsDomainModel domainModel) 
    { 
     Date = domainModel.Date; 
     Cost = domainModel.Cost; 
     // .... some other property mappings 
    } 
} 

Che cosa il vostro metodo di action su PurchaseController dovrebbe fare, sta orchestrando il processo di ottenere il vostro PurchaseRecordsDomainModel, creazione di PurchaseRecordsViewModel da PurchaseRecordsDomainModel e passandolo allo View. Il metodo Action non deve contenere alcun codice che riguarda la connessione e il recupero dei dati dal database (nel caso in cui si esegua l'interrogazione del contesto EF) o qualsiasi logica aziendale. Dovresti provare ad avere moduli liberamente accoppiati, parlando tra loro tramite abstractions, in questo modo assicurerai che la tua applicazione sia maintainable, extensible e testable.

Inoltre, provare a tracciare una chiara separazione tra vari livelli del sistema. Ad esempio, non è una buona idea avere EF entities come Domain Model Entites. Non vuoi che il tuo business logic layer dipenda da data access layer, pensa in questo modo, e se in un determinato momento, ti allontani dallo EF e usi qualche altro ORM o anche altra tecnologia per archiviare e interrogare i dati. Non vuoi cambiare business logic layer solo perché stai modificando il tuo data access layer. Quindi, passare dalle parole al codice nel tuo caso.

Considerando che avete già il vostro view e view model, vorrei creare PurchaseRecordsService di classe in domain layer (si prega di notare seconda nel tuo caso non si potrebbe utilizzare Repositories, ma qualche altra tecnica, questo esempio è principalmente per illustrare il mio punto)

public class PurchaseRecordsService 
{ 
    private readonly IPurchaseRecordsRepository _purchaseRecordsRepository; 
    public PurchaseRecordsService(IPurchaseRecordsRepository purchaseRecordsRepository) 
    { 
     if(purchaseRecordsRepository == null) 
     { 
     throw new ArgumentNullException("purchaseRecordsRepository"); 
     } 

     _purchaseRecordsRepository = purchaseRecordsRepository; 
    } 

    public IEnumerable<PurchaseRecordsDomainModel> GetPurchaseRecords() 
    { 
     // trivial case, real code can be more complex 
     return _purchaseRecordsRepository.GetPurchaseRecords(); 
    } 
} 

Poi, nel tuo domain layer, è possibile definire IPurchaseRecordsRepository

public interface IPurchaseRecordsRepository 
{ 
    IEnumerable<PurchaseRecordsDomainModel > GetPurchaseRecords(); 
} 

L'idea è, il nostro PurchaseRecordsService necessita di un modo per comunicare con i database, quindi chiunque lo utilizzi deve fornire l'implementazione di IPurchaseRecordsRepository. Il passo successivo è passare al nostro data access layer e creare la classe di implementazione di IPurchaseRecordsRepository.

public class EfPurchaseRecordsRepository: IPurchaseRecordsRepository 
{ 
    private readonly EfObjectContext _objectContext; 
    public EfPurchaseRecordsRepository(string connectionString) 
    { 
     _objectContext = new EfObjectContext(connectionString); 
    } 

    public IEnumerable<PurchaseRecordsDomainModel > GetPurchaseRecords() 
    { 
     var purchaseRecords = (from p in _objectContext.PurchaseRecords 
          .... 
          select p).AsEnumerable(); 

     return purchaseRecords .Select(p => p.ConvertToDomainPurchaseRecord()); 
    } 
} 

E l'ultimo pezzo - abbiamo bisogno di definire la nostra Action in PurchaseController

public class PurchaseController: Controller 
{ 
    private readonly IPurchaseRecordsRepository _repository; 

    public PurchaseController(IPurchaseRecordsRepository repository) 
    { 
     if(repository == null) 
     { 
     throw new ArgumentNullException("repository"); 
     } 
     _repository = repository; 
    } 

    public ActionResult Index() 
    { 
     var purchaseRecordsService = new PurchaseRecordsService(_repository); 

     var purchaseRecordsViewModel = new PurchaseRecordsViewModel(); 

     var purchaseRecords = purchaseRecordsService.GetPurchaseRecords(); 

     foreach(var purchaseRecord in purchaseRecords) 
     { 
      var purchaseRecordViewModel = new PurchaseRecordViewModel(purchaseRecord); 
      purchaseRecordsViewModel.PurchaseRecords.Add(purchaseRecordViewModel); 
     } 

     return View(purchaseRecordsViewModel); 
    } 
} 

Per ricapitolare, quello che abbiamo è debolmente accoppiati codice, i nostri Presentation e Data Access Livelli non conoscono l'un l'altro e dipendono solo dal livello Domain. Se è necessario, è possibile sostituire il front-end MVC con WPF ad esempio, passare da EF a un'altra tecnologia, il proprio codice è verificabile.

+2

Tutte e tre sono state buone risposte che mi hanno aiutato .. Mi è piaciuta anche la risposta di C Shaper ... ma hai un campione dettagliato! – aggie