Ideally, a PurchaseRecordViewModel should populate itself with a PurchaseRecordsDomainModel . It should contain a simple mapping of properties and possibly some formatting of the output that you intend to use in your view.
PurchaseRecordsViewModel
public class PurchaseRecordsViewModel { public IEnumerable<PurchaseRecordViewModel> PurchaseRecords {get;set;} }
PurchaseRecordViewModel
public class PurchaseRecordViewModel { public DateTime Date {get;set;} public decimal Cost {get;set;}
What your action method on the PurchaseController should do is organize the process of getting the PurchaseRecordsDomainModel , creating the PurchaseRecordsViewModel from the PurchaseRecordsDomainModel and passing it to the View . action method itself should not contain any code related to connecting and retrieving data from the database (in your case, requesting the EF context) or any business logic. You should try to have loosely coupled modules while talking to each other through abstractions , so you make sure your application is maintainable , extensible and testable .
In addition, try to make a clear separation between the different levels of your system. For example, it's nice to have EF entities as Domain Model Entites . You do not want your business logic layer depend on a data access layer , think about it so that if at some point in the future you move away from EF and use some other ORM or even other technologies to store and request data. You do not want to change the business logic layer just because you are changing your data access layer . So go from words to code in your case.
Given that you already have your View and view model , I would create the PurchaseRecordsService class in the domain layer (note that depending on your case, you may not use Repositories , but some other methods, this example mainly illustrates my point of view )
public class PurchaseRecordsService { private readonly IPurchaseRecordsRepository _purchaseRecordsRepository; public PurchaseRecordsService(IPurchaseRecordsRepository purchaseRecordsRepository) { if(purchaseRecordsRepository == null) { throw new ArgumentNullException("purchaseRecordsRepository"); } _purchaseRecordsRepository = purchaseRecordsRepository; } public IEnumerable<PurchaseRecordsDomainModel> GetPurchaseRecords() {
Then in the domain layer you can define IPurchaseRecordsRepository
public interface IPurchaseRecordsRepository { IEnumerable<PurchaseRecordsDomainModel > GetPurchaseRecords(); }
The idea is that our PurchaseRecordsService needs a way to communicate with the databases, so anyone who uses it must provide an IPurchaseRecordsRepository implementation. The next step is to go to our data access layer and create an implementation class 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()); } }
And the last fragment - we need to define our action in the 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); } }
Recall that we have loosely coupled code, our Presentation and Data Access Layers do not know about each other, and they depend only on the Domain level. If you need, you can replace the MVC front end with WPF , for example, move from EF to another technology, your code can be checked.