4

I'm using MVC (for the first time) with Entity framework, Database first

What I want to do is display data from a database in a single view. I created the database first, then I made a ADO.NET Entity Data Model based from the database that contains all the tables. I then created a Index view that was strongly typed with my Entity Data Model as model.

In my Index I have at the top

@model IEnumerable<Forum6.Models.Forum>

This allows me to get the rows from the table "Forum" from my database. If I try to add an extra model I get I get this error message when I run:

Line 1: @model IEnumerable<Forum6.Models.Forum>
Line 2: @model2 IEnumerable<Forum6.Models.Post>  

Parser Error Message: Only one 'model' statement is allowed in a file.

After searching for an answer I found this: Two models in one view in ASP MVC 3 The answer was to create a ViewModel (ParentModel) that contained all the Models (Tables). This is the ViewModel I created:

public class ViewModel
{
    public IEnumerable<Forum6.Models.Forum>         Forum       { get; set; }
    public IEnumerable<Forum6.Models.Post>          Post        { get; set; }
    public IEnumerable<Forum6.Models.Topics>        Topics      { get; set; }
    public IEnumerable<Forum6.Models.Users>         Users       { get; set; }
    public IEnumerable<Forum6.Models.PrivMsg>       PrivMsg     { get; set; }
    public IEnumerable<Forum6.Models.Permission>    Permission  { get; set; }
}

I edited my controller to look like this:

   public class HomeController : Controller
{
    // ForumDBEntities old_db = new ForumDBEntities();

    ViewModel db = new ViewModel();

    public ActionResult Index()
    {
        return View(db);
    }
}

Then replaced the old Index view with a new strongly typed view that used the ViewModel as model. Which contains:

@model IEnumerable<Forum6.Models.ViewModel>

Trying to run this gives me this error:

The model item passed into the dictionary is of type 'Forum6.Models.ViewModel', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Forum6.Models.ViewModel]

How do I make the "ViewModel" enumarable? Or is my error elsewhere?

Community
  • 1
  • 1
NoClueBlue
  • 451
  • 4
  • 17
  • pass ViewModel as model to your view: @model ViewModel – Sergio Mar 12 '13 at 11:59
  • Sorry, forgot to include what my view contains. Edited my answer to include. "@model IEnumerable" – NoClueBlue Mar 12 '13 at 12:07
  • Judging from what I can see, are you sure that your viewmodel should be IEnumerable? Since all the items inside are, just as you did in your first try. – Snæbjørn Mar 12 '13 at 12:08
  • I removed "IEnumrable" from ViewModel, but I still get the same error. I think I have to get the controller to pass an Enumerable ViewModel, but I haven't figured it out yet. – NoClueBlue Mar 12 '13 at 12:36
  • How do you merge the models in your viewmodel? Could you post that code – Snæbjørn Mar 12 '13 at 12:55
  • Isn't that what I have done in the "ViewModel" that I have posted? I'm starting to think I've made my ViewModel wrong... – NoClueBlue Mar 12 '13 at 13:07
  • You've showed what ViewModel consists of, not how you create it. Unless `ViewModel db = new ViewModel();` that is how, but then you might as well do `return View(new ViewModel());` and then having `@model Forum6.Models.ViewModel` in your view should work, except the model is empty – Snæbjørn Mar 12 '13 at 13:16
  • Aha, so how should I go about populating my ViewModel with data? – NoClueBlue Mar 12 '13 at 13:26
  • Yep you need to fill it with data. You've only defined what should be in there but you haven't put any real data in there so everything is default values, which is null in this case. – Snæbjørn Mar 12 '13 at 13:35

2 Answers2

10

You'll need to change @model IEnumerable<Forum6.Models.ViewModel> to @model Forum6.Models.ViewModel as you're wrapping your IEnumerables inside a single ViewModel.

A good rule of thumb is to have a 1:1 relationship between your ViewModel and View. enter image description here

This might be a good read for you: http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ (just ignore the automapper part if you don't want to go that route)

You'll also need to put in actual data in your ViewModel since

ViewModel db = new ViewModel();

public ActionResult Index()
{
    return View(db);
}

will just give your view an empty ViewModel. One way to do it would be.

public ActionResult Index()
{
    var model = new ViewModel
                    {
                        Forum = db.GetForum(),
                        Post = db.GetPost(),
                        Topic = you get the idea
                    };

    return View(model);
}

One last thing when naming properties or variables in general you should use the plural verb when it contains a list. So your ViewModel would be.

public class ViewModel
{
    public IEnumerable<Forum6.Models.Forum>         Forums      { get; set; }
    public IEnumerable<Forum6.Models.Post>          Posts       { get; set; }
    public IEnumerable<Forum6.Models.Topics>        Topics      { get; set; }
    public IEnumerable<Forum6.Models.Users>         Users       { get; set; }
    public IEnumerable<Forum6.Models.PrivMsg>       PrivMsgs    { get; set; }
    public IEnumerable<Forum6.Models.Permission>    Permissions { get; set; }
}
Snæbjørn
  • 10,322
  • 14
  • 65
  • 124
  • I am trying same but methods of respective Models are not getting exposed. Why is like that? Do I need to create method in ViewModel too? – Volatil3 Jun 18 '14 at 20:29
1

Change @model IEnumerable<Forum6.Models.ViewModel> to @model Forum6.Models.ViewModel as you are passing a single instance of a ViewModel class and not a collection of them.

All your collections are passed in a single instance of a view model.

Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
  • Perhaps it should be the other way round? I should pass a collection of ViewModel to the View. If I don't do that I wont be able to run a "@foreach (var item in Model) {...}" – NoClueBlue Mar 12 '13 at 12:18
  • No, that way is correct. One view model that can contain some collections inside. – Jakub Konecki Mar 12 '13 at 13:04