In ASP.NET MVC, Where should one work with view models?
Should this be done strictly in the controller? Or would it be ok to say, return a view model from a repository method?
To my mind viewmodels are specific to whatever application is going to use them, whereas a repository would return a model common to all applications. So I'd say the view model should be created within the web site, from a common model returned from the repository, rather than tie the repository into knowing about how views are laid out.
Strictly speaking your repository should return domain objects
Repository: "Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects."
Fowler (PoEAA)
Viewmodels should be instantiated in your controller and passed to the strongly-typed view. Typically a ViewModel will contain multiple model types necessary to render your view. Here's a Quick Example:
Say you have two model objects Orders and Customer
You want to display Customer Details at the top of the page and a Grid of Orders in the Index view for that customer.
public class CustomerModel
{
//properties
}
public class OrderModel
{
//properties
}
public class CustomerVM
{
public CustomerModel customer { get; set; }
public IEnumerable<OrderModel> orders { get; set; }
}
//and in your controller
public class CustomerController : Controller
{
public ActionResult Index(int id)
{
CustomerVM vm = new CustomerVM();
vm.customer = CustomerRepository.GetCustomer(id);
vm.orders = OrdersRepository.GetOrdersForCustomer(id);
return View(vm);
}
}
repository should be a in between your domain and UI - the repository should know nothing about your UI layer - so you can get the best re-use and decoupling from it as possible.
Related
How can I use multiple models in a single view page in an MVC application?
The ViewModel exists for the exact reason you mention. Its primary purpose is to service the View. Its the place where you mix up multiple models and provide the View with a single data structure
Imagine you have below models:
public class A { }
public class B { }
You should create a ViewModel Class like below code:
public class ABViewModel
{
public A A {get;set;}
public B B {get;set;}
}
then update your view accepted model:
#model ABViewModel
And finally, you should pass this ViewModel to your view. good luck
I am using Entity Framework code first in a test project. I have distributed code in different layers as below
Model Layer
This layer is reference in all other layers/projects
namespace Model
{
Public class Sample
{
Public string Name
[ForeignKey("Category")]
public int CatrgoryId
Public Category Category
}
}
DAL
namespace DAL
{
public class SampleContext:DbContext
{
...
}
}
In DAL I only have the context class and migrations
BLL
namespace BLL
{
public class SampleBLL
{
public List<Sample> GetAll()
{
retrn new SampleContext().Samples().ToList()
}
}
}
UI
namespace UI
{
public class UIHelper
{
public List<Sample> GetSamples()
{
return new SampleBLL().GetAll();
}
}
}
It does not seem practical to use EF entity model objects in UI as they might have navigation properties and cannot be directly bound to controls like DataGridView because in that case the datagridview will have both the CategoryId and Category columns while I need to display the Category Name as Category eg DataGridView.DataSource = new SampleBLL().GetAll()
One solution that I could think of is to use ViewModel classes and manually map the entity model objects to viewmodel objects in BLL and return viewmodel objects to UI, But, introducing a new layer ViewModel would mean replicating all my Model objects with minor changes.
Forexmple the view model for above sample model would
namespace Model
{
Public class Sample
{
Public string Name
public int CatrgoryId
public string CategoryName
}
}
Is the viewmodel layer only option I have or there is an other efficient way to consume the Entity Models directly in UI.
It is a very bad idea to use Entity Models directly in UI, mainly because of the issues you've exposed. More importantly, you're currently only retrieving data and displaying it "as is", but the slightest change in UI affects DB, and vice-versa. Any more complexe logic would be very troublesome to implement, AFAIK
At work, we use a Transport namespace to store classes corresponding to our entities and assemblers methods to convert entities to transport classes once we're done with retrieval logic. This way we're separating model from controller, and can safely manipulate data without any risk of unwantingly affecting the database.
A few queries on EF.
Questions -
Should the methods that directly use database context object be part of Controller classes or Models?
ContactManagerContext.cs (which I am considering as a DAL layer?) Is my assumption correct?
Where should the ContactManager class be placed? Model or DAL? It is currently part of the Model class.
will add more questions
This is how I have structured the classes - Models and Controllers.
Please review and comment on if the code is structured correctly or not and how it can be improved.
Model class (Contact.cs):
using Contact_Manager.DAL;
namespace Contact_Manager.Models
{
public class Contact
{
[Key]
public int ContactId { get; set; }
[Required, MaxLength(100)]
public string FirstName { get; set; }
[Required, MaxLength(100)]
public string LastName { get; set; }
public string EMail { get; set; }
public string Phone { get; set; }
public string BusinessName { get; set; }
}
public class ContactManager
{
ContactContext db = new ContactContext();
public IEnumerable<Contact> ContactList(int? selectedContact)
{
IQueryable<Contact> contacts = db.Contacts;
return contacts.ToList();
}
}
}
ContactManagerContext.cs (DAL)
------------------------------
using System.Data.Entity;
using System.Linq;
using Contact_Manager.Models;
namespace Contact_Manager.DAL
{
public class ContactContext : DbContext
{
public ContactContext()
: base("ContactMgrDBContext")
{
Database.SetInitializer<ContactContext>(new DropCreateDatabaseIfModelChanges<ContactContext>());
}
public DbSet<Contact> Contacts { get; set; }
}
}
ContactController.cs (Controller class):
using System.Web.Mvc;
using System.Linq;
using Contact_Manager.Models;
namespace Contact_Manager.Controllers
{
public class ContactController : Controller
{
//
// GET: /Contact/
public JsonResult ContactList()
{
ContactManager cMgr = new ContactManager();
IEnumerable<Contact> contactList = cMgr.ContactList(0);
//var contactsJson = JsonConvert.SerializeObject(contacts.ToList());
return Json(contactList, JsonRequestBehavior.AllowGet);
}
public ActionResult Index()
{
return View();
}
}
}
The MVC pattern is one of the most misunderstood architecture patterns.
Also if it is used very often in UI it is a more general approach. The common usage has to be separated from the aim to adress different responsibilities.
The best way to explain MVC is to see it as a pattern that separates responsibilities AND the collaboration between them in ONE layer. So you may have MVC in the UI-Layer, but also in the DAO-Layer.
For example in the UI-Layer a model object is an object that holds the state of a UI-Component. The View-Object is the UI-Component that holds logic to draw itself on base of the model object state. The Controller retreives events from different sources and orchestrates communication between model and view.
In the DAO-Layer the model object is a part of a database state (often a row). Think of an ORM-Object. The view object is the representation for the "next" layer. The controller is the DAO that orchestrates mappings and changes.
In general you need something that holds a STATE (model). Then you need an external representaion of the STATE to PUBLISH (view) avoiding coupling to the STATE. After all you have to have BEHAVIOUR (controller) orchestrate changes and mappings.
The approach to see MVC as layers may work for small projects. In larger projects you will face problems in maintainability because you have definitely MORE than three responsibilities. And if you only have three layers you will mix responsibilities lacking the Single Responsibility Principle.
To answer your questions:
No. Write a separate DAO for that. The controller and/or the model should use that.
No. See 1.
If we talk about MVC the controller is the controller. Nothing else. If we talk about layers the controller seems to mix responsibilities of UI, Model maybe DAO. So the assignment is ambiguous.
You can you the three Layers' model in the Controller part. the Controller will be the highest layer, and it will "talk" with the BL and so on.
The Models suppose to be simple and clean.
I'm running into a weird issue. I'm using MVC 4, and I'm trying to pull data from two separate tables to pass into my view. Normally I'd just build a model to handle this, but these two tables are already used in other models, so when I try to create a new model, there's issues with ambiguity.
I guess my question is this: what's the best way to pull data from two separate tables on a database and get it into a view? For some reason, the whole concept of Entity Framework is a little confusing to me, so maybe I'm missing something simple here.
Also, if anyone has any place where I can read up on some pretty comprehensive database interactions using EF, I'd really appreciate it (though I guess I could just google that)
The best way will be to create a ViewModel and add the 2 models inside of it.
So you will need to create something like
public class MyViewModel
{
public MyFirstEntity FirstEntity{ get; set; }
public MySecondEntity SecondEntity{ get; set; }
}
And in your controller do something like this:
public ActionResult Index(int someparameter)
{
MyFirstEntity firstEntity=
BusinessLogic.GetMyFirstEntity(someparameter);
MySecondEntity secondEntity=
BusinessLogic.GetMySecondEntity(someparameter);
MyViewModel myViewModel = new MyViewModel
{
FirstEntity = firstEntity,
SecondEntity= secondEntity
};
return View(myViewModel);
}
Also you can check this blog post for more information on the matter.
Typically, your view model would only pass the view the information it requires. If implemented correctly, the view model should not know or care where the information has comes from.
In your case, you would create the view model based upon the data from the two tables, rather than using the two tables themselves.
The following is an example of what you could do:
public ViewResult MyActionMethod()
{
var tableOne = MyDataRepository.GetDataFromTableOne();
var tableTwo = MyDataRepository.GetDataFromTableTwo();
var model = new MyActionMethodModel()
{
Property1 = tableOne.Property1,
Property2 = tableTwo.Property2,
};
return this.View(model);
}
I've created my application and using the database first approach. So I used the ADO.net Entity Data Model to add my database to the project and then added controllers to it that way, I don't have any models so to speak I think? But anyway, I've added controllers and CRUD was added to each entity automatically.
My problem is, I want to view data from many tables on one web page. I can do this via sql but how do I use sql to pull the data I need and display it on the screen.
To build a little bit on Dave A's answer:
I personally like doing this type of retrieval with database first EF.
After building the EDMX, create a simple, straight-forward POCO that mimics what you want to return. A simple example would be:
public class ComplexModelFromMultipleTables
{
List<Car> Cars { get; set; }
List<Bike> Bikes { get; set; }
List<Boat> Boats { get; set; }
}
Once you've built the relationships in your database which is reflected in your EDMX, access it in a provider via your favorite pattern. A simple using pattern is always good, though I've built the more complex object with a mapper.
public ComplexModelFromMultipleTables GetObject
using (var db = new DBContext())
{
var model = new ComplexModelFromMultipleTables
{
Cars = db.Cars.Where(x => x.CarType == whateveryouwant).ToList(),
Bikes = db.Bikes.Where(x => x.anotherproperty == whateveryouwant).ToList(),
Boats = db.Boats.Where(x => x.something else == whateveryouwant).ToList(),
}
return model;
}
Call this provider from your controller and strongly type the view with
#model ComplexModelFromMultipleTables
at the top of your view.
I assume that you are referring to EF Code First approach to creating an Entity Model.
If I'm right, your conflicted by the common practice of using Entities (Table mapped classes) as Models to your Views.
I often use Entities as Models when I first scaffold a page. But As you've found, they are rarely appropriate and I often find myself migrating to more Robust Models.
1) I recommend you create a class library in your Models Directory. Embed make several Entities members of your class.
Forexample, you can have a CustomeActivityModel which also has as members of Customers, Sales, and Orders.
class CustomeActivityModel
{
Customers CustomerList { get; set; }
Sales SalesList { get; set; }
Orders OrdersList { get; set; }
}
within you Controller, you would populate them
ViewResult Index()
{
CustomeActivityModel Model = new CustomeActivityModel();
Model.CustomerList EFContext.Customers;
Model.SalesList EFContext.Sales;
Model.OrdersList EFContext.Orders;
Return View(Model);
}
or alternatively, you can use EF's Linq ability to include Entities that have key relationships (assuming Sales has foreign key for Customers and Orders)
ViewResult Index()
{
Model = EFContext.Sales.include("Customers").include("Orders");
Return View(Model);
}