Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use multiple models in one view for ASP.NET MVC?

I've read similar questions on SO but can't seem to figure out this issue, which is specific to DBContext objects (I think). Here's some dummy code to illustrate.

I have the following code in my Index() action:

    public ActionResult Index()
    {
        AnimalDBContext db = new AnimalDBContext();

        return View(db.Dogs);
    }

I have the following code for my models:

    public class Dog
    {
        public int ID { get; set; }
        public string name { get; set; }
        public string breed { get; set; }
    }

    public class AnimalDBContext : DbContext
    {
        public DbSet<Dog> Dogs { get; set; }
    }

In my view I have the following:

@model IEnumerable<AnimalProject.Models.Dog>
    @foreach (var d in Model)
    {
    <h3>@d.name</h3>
    <h2>@d.breed</h2>
    }

Everything works great, the view will loop through every dog in my database. However, I have another set of DBContext data from another table that I want in the same view. I want to be able to enumerate each item in the database for that table as well.

This is what I want, if you catch my drift:

@model IEnumerable<AnimalProject.Models.Dog>
@model IEnumerable<AnimalProject.Models.Cat>
    @foreach (var d in Dog)
    {
    <h3>@d.name</h3>
    <h2>@d.breed</h2>
    }
    @foreach (var c in Cat)
    {
    <h3>@c.name</h3>
    <h2>@c.breed</h2>
    }

I have tried grouping the classes together and using a partial view, but apparently you can't have a different model in a partial view, because I always get the error message:

"The model item passed into the dictionary is of type 'System.Data.Entity.DbSet1[AnimalProject.Models.Dog]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[AnimalProject.Models.Cat]'."

So, how can I use multiple models in my view that both get the data I want from separate tables in the database?

like image 230
Monochrome Avatar asked Apr 29 '11 07:04

Monochrome


2 Answers

What about creating custom view model class:

public AnimalModel
{
    public IEnumerable<Dog> Dogs { get; set; }
    public IEnumerable<Cat> Cats { get; set; }
} 

Fill this model in Index and pass it to the view which will expect AnimalModel instead of enumerables.

Edit:

Filling the model:

public ActionResult Index()
{
    using (var db = new AnimalDBContext())
    {
        var model = new AnimalModel 
        {
            Dogs = db.Dogs.ToList(),
            Cats = db.Cats.ToList()
        };

        return View(model);
    }
}

View (I have never used Razor so I hope this is correct):

@model AnimalProject.Models.AnimalModel
@foreach (var d in Model.Dogs)
{
  <h3>@d.name</h3>
  <h2>@d.breed</h2>
}
@foreach (var c in Model.Cats)
{
  <h3>@c.name</h3>
  <h2>@c.breed</h2>
}
like image 77
Ladislav Mrnka Avatar answered Oct 10 '22 20:10

Ladislav Mrnka


A model is just an object like any other object in C# (or VB)

So you can pass any object you want to the view, even complex ones. If you need to present a lot of things, then create a view model (a model just for the view's needs) which contains all the things you want to present and pass this one to the view. Then, from within the view, you access the model's individual properties on the different parts of the view, to present them. An example of this approach is the Animal Model Ladislav Mrnka talked about. You put in there the dogs and cats enumerables and then pass it to the view. You tell the view that your model now is this AnimalModel type etc etc...

So, since a model is just an object, and if you are lazy enough to not want to create another custom view model, then you can pass your whole dbcontext as a model to the view like this.

Controller

public ActionResult Index()
{
   return View(new AnimalDBContext()); // We pass a new instance of the dbcontext to the view
}

View

@model AnimalProject.AnimalDBContext // we declare that our model is of type AnimalDBContext 
@foreach (var d in Model.Dogs) // We reference the dbcontext's sets directly
{
  <h3>@d.name</h3>
  <h2>@d.breed</h2>
}
@foreach (var c in Model.Cats) // We reference the dbcontext's sets directly
{
  <h3>@c.name</h3>
  <h2>@c.breed</h2>
}

Now you have declared to your view that your "Model" object will be an AnimalDBContext So you can access all the AnimalDBContext's properties, sets etc directly from within your view. It may not be the best abstraction for the data access, but look how simple your controller has become! :) You just throw the whole world into the view and let it decide which parts to pick and present... Of course this is for simple scenarios. If you wanted more complex stuff you would have to fall back to custom view models eventually.

like image 24
Thanasis Ioannidis Avatar answered Oct 10 '22 22:10

Thanasis Ioannidis