0

I'm an inch away from getting my Create form working. My problem is that some data passed into the form in the view model isn't being sent back in the postback.

Models:

Game:
    GameID - int (primary key, auto-incr)
    GameTitle - nvarchar(100)
    ReviewText - text
    ReviewScore - smallint
    Pros - text
    Cons - text
    LastModified - Datetime
    GenreID - int (foreign key from Genres)

Platform:
    PlatformID - int (primary key, auto-incr)
    Name - nvarchar(50)

GamePlatform (not visible as an EF 4 entity):
    GameID - int (foreign key from Games)
    PlatformID - int (foreign key from Platforms)

The view models I'm using:

public class PlatformListing
{
    public Platform Platform { get; set; }
    public bool IsSelected { get; set; }
}

public class AdminGameReviewViewModel
{
    public Game GameData { get; set; }
    public List<Genre> AllGenres { get; set; }
    public List<PlatformListing> AllPlatforms { get; set; }
}

And the form itself:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<HandiGamer.WebUI.ViewModels.AdminGameReviewViewModel>" %>

<p>
    <%: Html.Label("Game Title") %>
    <%: Html.TextBoxFor(model => Model.GameData.GameTitle) %>
    <%: Html.ValidationMessageFor(model => Model.GameData.GameTitle) %>
</p>
<p>
    <%: Html.LabelFor(model => Model.GameData.GenreID) %>
    <%: Html.DropDownListFor(m => Model.GameData.GenreID, new SelectList(Model.AllGenres, "GenreID", "Name", Model.GameData.GenreID)) %>
</p>
<p>
    <%: Html.Label("Platforms") %><br />
    <% for(var i = 0; i < Model.AllPlatforms.Count; ++i)
       { %>
           <%: Model.AllPlatforms[i].Platform.Name %> <%: Html.CheckBoxFor(p => Model.AllPlatforms[i].IsSelected) %>
    <% } %>
</p>
<p>
    <%: Html.Label("Review") %>
    <%: Html.TextAreaFor(model => Model.GameData.ReviewText) %>
</p>
<p>
    <%: Html.Label("Review Score") %>
    <%: Html.DropDownListFor(m => Model.GameData.ReviewScore,  new SelectList(new int[] {1, 2, 3, 4, 5}))%>
</p>
<p>
    <%: Html.LabelFor(model => model.GameData.Pros) %><br />
    <%: Html.TextAreaFor(model => model.GameData.Pros) %>
</p>
<p>
    <%: Html.LabelFor(model => model.GameData.Cons) %><br />
    <%: Html.TextAreaFor(model => model.GameData.Cons) %>
</p>

And, finally, my Create method (barebones as I'm trying to get this to work):

    [HttpPost]
    public ActionResult CreateReview([Bind(Prefix = "GameData")]Game newGame, [Bind(Prefix = "AllPlatforms")]List<PlatformListing> PlatformList)
    {
        try
        {
            foreach(var plat in PlatformList)
            {
                if (plat.IsSelected == true)
                {
                    newGame.Platforms.Add(plat.Platform);
                }
            }

            newGame.LastModified = DateTime.Now;

            _siteDB.Games.AddObject(newGame);
            _siteDB.SaveChanges();

            // add form data to entities, then save
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

The problem is, of course, with my checkboxes. The boolean isSelected is being set fine, but when the data is being posted, the corresponding Platform object is missing. I thought they would automatically be passed back. So, any suggestions on how to pass back the actual Platform part of a PlatformListing?

Major Productions
  • 5,914
  • 13
  • 70
  • 149

1 Answers1

1

Regarding getting the checkbox values, how about using the strategy described here?

Regarding passing around entity objects as arguments, I'd say you're letting your data layer get mixed into your view layer, and you should use a dedicated ViewModel.

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • I'm not sure I understand what you mean by 'use a dedicated ViewModel'. I thought view models were supposed to be one way only - derived from the model, and passed to the view via the controller. I don't see why I shouldn't expect to get back actual model data on form post. It doesn't make sense to me to funnel that data back through the view model only to have to disassemble it and store it in the model. What am I missing? – Major Productions Nov 16 '10 at 22:42
  • @kevinmajor1: You can also have Input models, to model the data that's being passed from the view into your action. By separating your data, business, and view layers, you make your code more modular. For example, how do you unit test your controller action? You can't (at least not easily) because you're doing database access right within your action. I could give this action the same inputs and come up with completely different results depending on what data was already in the database. – StriplingWarrior Nov 16 '10 at 23:19
  • Right, but right now I simply want to be able to correctly create a Game. I know that TDD is the right way to go, but I'm still a beginner with all of this. Unit testing isn't a realistic concern of mine at the moment. Simply being able to take data from a form and write it to a db by using EF is what I need to get a handle on before I tackle more complex topics. I want to be able to do this the right way, but first I need to get a feel of how the bare bones basics actually work. – Major Productions Nov 17 '10 at 01:25
  • @kevinmajor1: That's fine. Those are the kind of decisions each developer must make on a project-by-project basis. Good luck. – StriplingWarrior Nov 17 '10 at 03:47