viewmodelienumerablemultiple-tablesasp.net-mvc-5

MVC 5 Viewmodel and multiple tables


I've just finished 2 views, an insert and a index view and I have to say, it's not easy dealing with multiple tables. The "insert" was the easiest, I just had to add to 2 different tables:

[HttpPost]
public ActionResult Index(CustPlayerVM custPlayer)
{
    var Cust = new Cust()
    {
        CustID = custPlayer.CustID,
        Color = custPlayer.Color
    };
    var Player = new Player()
    {
        PlayerName = custPlayer.PlayerName
    };
    db.Custs.Add(Cust);
    db.Players.Add(Player);
    db.SaveChanges();
    return View();
}

The problem is that I had ALL kinds of errors with List<> and IEnumerable<> trying to code the view. Either you get the dreaded "model item passed into the dictionary is of type" error or the null reference in the view when the "foreach" loop was processed. It was a miracle that this worked, but I can't tell you why. That's why I posted the question to begin with.

Here's what the "view" looks like:

public ActionResult List()
{
    ViewBag.Message = "custPlayer";
    //CustPlayerVM vm = new CustPlayerVM();      

    List<object> vm = new List<object>();
    vm.Add(db.Custs.ToList());
    vm.Add(db.Players.ToList());          
    ViewBag.PlayerCnt = db.Players.Count();
    return View(vm);
}

Notice the List<object> (as opposed to view model that's commented out).

And this is the view:

@model IEnumerable<object> @{ 
    List<viewModelA.Cust> lstCust = Model.ToList()[0] as List<viewModelA.Cust>;
    List<viewModelA.Player> lstPlayer = Model.ToList()[1] as List<viewModelA.Player>; }   

@Html.ActionLink("Create New", "Create") </p> 
<table class="table">
    <tr>
        <th>
            @Html.Raw("Color")
        </th>
        <th>
            @Html.Raw("CustID")
        </th>
        <th>
            @Html.Raw("ID")
        </th>
        <th>
            @Html.Raw("Player Name")
        </th>
        <th>
            @Html.Raw("PlayerID")
        </th>
    </tr>
    &nbsp;
    @for (int i = 0; i < ViewBag.PlayerCnt; i++)
    {
        <tr>
            <td>@lstCust[i].Color</td>
            <td>  @lstCust[i].CustID</td>
            <td>  @lstCust[i].ID </td>
            <td>   @lstPlayer[i].PlayerName  </td>
            <td> @lstPlayer[i].ID</td>
        </tr>
    } 
</table>

I had to wrap a for loop around the code because the foreach ran for each table separately.

In the future, how are you supposed to deal with IEnumerable vs anonymous types? It shouldn't be this hard, correct?


Solution

  • To improve your code I strongly recommend to investigate more in OOP basics and .NET basics, including how to work with collections (Array, List, Collection, IEnumerable, foreach).

    Then the following ideas will be obvious:

    1. Create a common ViewModel class, which will represent the state of the View

       class PersonViewModel
       {
          public int CustID { get; set; }
          public string Color { get; set; }
          public string PlayerName { get; set; }
       }
      
    2. Use this common class for your view

       public ActionResult List()
       {
          var viewModel = new List<PersonViewModel>();      
          viewModel.Add(db.Custs.ToArray());
          viewModel.Add(db.Players.ToArray());          
      
          return View(viewModel);
       }
      
    3. Instead of a list of generic Object type apply a collection of your PersonViewModel type

           @model IEnumerable<PersonViewModel>
      
           <table class="table">
             @foreach(var personVM in Model){
               <tr>
                  <td>@personVM.Color</td>
                  <td>@personVM.CustID</td>
                  <td>@personVM.PlayerName</td>
               </tr>
              } 
           </table>