In ASP.NET MVC, how can you utilize several models in one view?

asp.net-mvc entity-framework

Question

I've seen related queries on SO, but I'm having trouble understanding this problem that just affects DBContext objects (I think). Here is some example fake code.

My Index() action has the code below:

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

        return View(db.Dogs);
    }

For my models, I have the following code:

    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; }
    }

I believe the following to be true:

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

The view will cycle over each dog in my database, and everything works well. I do, however, wish to include additional DBContext data from a different database in the same view. For that table as well, I want to be able to enumerate every object in the database.

If you get what I'm saying, then I want this:

@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 using a partial view and grouping the classes together, but evidently you cannot use a different model in a partial view since I consistently get the following 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]'."

How then can I utilize many models in my view, each of which gets the data I need from different database tables?

1
7
4/5/2012 4:10:48 PM

Accepted Answer

How about developing a unique view model class?

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

Index this model and provide it to the view, which will anticipateAnimalModel rather than enumerables.

Edit:

Complete 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 hope this is accurate; I haven't used Razor):

@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>
}
13
4/29/2011 8:44:12 AM

Popular Answer

In C#, a model is merely another kind of object (or VB)

Therefore, you are free to send any object—even complicated ones—to the view. If you need to convey a lot of information, make a view model (a model created specifically for the purposes of the view) that includes all you need to present and provide it to the view. Then, in order to show them, you access the model's various attributes on each of the view's component elements from inside the view. Ladislav Mrnka's mention of the animal model as an illustration of this strategy. You fill it with the enumerable canines and felines before passing it to the viewer. You inform the view that your model is now an AnimalModel type, etc.

Since a model is only an object, if you are too lazy to create another custom view model, you may simply give your whole database context to the view in this manner.

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>
}

You have now specified in your view that your "Model" object will be an AnimalDBContext, allowing you to immediately access all of the AnimalDBContext's properties, sets, and other elements. Although it may not be the ideal abstraction for data access, notice how straightforward your controller has become: You just toss the whole universe into the view, and it chooses which elements to choose and display... Of course, these are straightforward situations. Eventually, you would have to resort to custom view models if you want more complicated items.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow