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
Related
In my ASP.NET MVC4 Web Application I'm trying to display a table with some information from a SQL database using Entity Framework. Generating a view from the SQL table(using database firs with EF) was easy for me to do, but now I'm stuck on a more conceptual question. Right now my controller passes the list of entity objects to my view.
public ActionResult Index()
{
return View(db.APU_daily_summary_test.ToList());
}
But now I need to calculate the min and max of some of these columns in SQL. I know that I should calculate the min and max inside the model, but after that I don't know how I should pass this information through the controller to the view. Do I need a view model? An API? An extra controller?
You just described a perfect use case for a View Model.
Here's the structure I would recommend:
public class MyViewModel
{
public int MaxOfColumn { get; set; }
public List<InnerViewModel> Items { get; set; }
}
public class InnerViewModel
{
// Create properties here which represent the Model's columns you need to display
}
Not only does a view model help break it up so you don't have to do many data operations within your view. This also breaks a very common bug with more complex models where the EF object has a circular reference.
You could use a view model..
public class MyViewModel
{
public List<MyType> MyList { get; set; }
public int MaxVal { get; set; }
public int MinVal { get; set; }
}
... and associate your view with the model...
or simply call the aggregated LINQ functions Max and Min from your view:
{# int max = Model.Max(x => x.MyColumn); }
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.
I have a good understanding of EF, and generated my database successfully. Now, I am struggling with adding dynamic properties to one of the entity classes. For example, I have a Post class, and other users can make comments to the posts. When I list the existing posts, I want to display the number of comments made to corresponding post.
One solution might be having a property called CommentCount, and updating the Post by increasing the (int) value of the CommentCount property by 1 when a new comment is made.
The other solution, and I think it is a better solution, is that when retrieving the post from the DB, the number of comments associated with the post can be computed and retrieved at the same time and assigned to CommentCount property of the post instance. However, I do not know how to achieve this with EF.
Which approach is highly recommended? Or, is there any other ways of doing this? If it is the second one, how can I achieve this with EF?
1) You should simply consider not putting the property called CommentCount into your model. When you develop for example a WPF Windows application, you should consider using MVVM pattern and the CommentCount would belong to your ViewModel class and not to your Model class. There you implement INotifyPropertyChanged and you can use it from your frontend Views. Analogically there is MVC pattern for ASP.NET etc.
There are other design patterns like Repository pattern. Using this pattern you can create the CommentCount in your repository class and not in your
model class. This would be similar to your second solution.
2) I assume from your question that you are using code-first approach:
generated my database successfully
If you do so and you wish to include CommentCount directly in your Model class, you can do it this by adding partial class file to your project like this:
namespace DBModel.Models
{
public partial class Post
{
public int CommentsCount
{
get { return this.Comments.Count; }
}
...
But I cannot see why to create extra property in your model just for that.
On the other hand adding this field as a computed field into your SQL database could make sense and then it would be part of your EF model.
If you calculation is very complex you should try creating a View in your DB and then add it to your Model?
But if your Model have something simple like
class Post {
public int postid { get; set; }
public virtual ICollection<comment> comment { get; set; }
}
In your controller you can do
db.post(x => x.postid == yourid).comments.count()
to get total of comment
or in your view
#foreach (var item in Model)
{
<li>item.postid;</li>
<li>item.comment.Count();</li>
}
Or update your class
class Post {
public int postid { get; set; }
public virtual ICollection<comment> comment { get; set; }
public int CommentCount
{
get
{
return comment.Count();
}
}
}
Just remember bring related data in your query.
In my case POI have properties parish_id, sector_id, city_id and parish have municipality, and municipality have state.
Using this query I can get Poi with all the related data.
filter = db.poi
.Include("parish")
.Include("sector")
.Include("city")
.Include("parish.municipality")
.Include("parish.municipality.state")
.Where(x => x.sector_id == SectorID);
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);
}
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.