If got a couple of linqTOsql objects that I am trying to edit through a form.
First, there’s the Stream class:
[Table]
public class Stream
{
[HiddenInput(DisplayValue = false)]
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public long StreamID { get; set; }
/*other properties removes for brevity*/
// relationship (one stream to many Stream2FieldTypes)
// uses EntitySet<Stream2FieldTypes> and OtherKey for the FK in Stream2FieldTypes
private EntitySet<Stream2FieldTypes> _Stream2FieldTypes;
[System.Data.Linq.Mapping.Association(Storage = "_Stream2FieldTypes", OtherKey = "StreamID")]
public EntitySet<Stream2FieldTypes> Stream2FieldTypes
{
get { return this._Stream2FieldTypes; }
set { this._Stream2FieldTypes.Assign(value); }
}
}
Then there’s the Stream2FieldTypes class:
[Table]
public class Stream2FieldTypes
{
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public long s2fID { get; set; }
/*other properties removed for brevity*/
[Column]
public long StreamID { get; set; } // FK
// relationship (one Stream2FieldTypes to Streams)
private EntitySet<Stream> _Stream;
[Association(Storage = "_Stream", ThisKey = "StreamID")]
public EntitySet<Stream> Stream
{
get { return this._Stream; }
set { this._Stream.Assign(value); }
}
}
I use the linqTOsql repository to get these objects and send them to the view like this:
public ActionResult StreamEdit(long id)
{
Genesis.Domain.Entities.Stream stream = genesisRepository.Streams.FirstOrDefault(x => x.StreamID == id);
return View(stream);
}
Everything get’s sent to the view without a problem… But when the form on the view is submitted, the Stream.Stream2FieldTypes gets lost for some reason. I catch the form submission with this action:
[HttpPost]
public ActionResult StreamEdit( long id, Genesis.Domain.Entities.Stream form)
{
return View(form);
}
And the view is without the Stream2FieldTypes collection.
The view is writing the Stream2FieldTypes like this:
<% for (int i = 0; i < (Model.Stream2FieldTypes != null ? Model.Stream2FieldTypes.Count() : 0); i++) %>
<% { %>
<div class="ListItem">
Label: <%: Html.EditorFor(x => x.Stream2FieldTypes[i].s2fLabel, new { style="width:100px" })%>
Required: <%: Html.EditorFor(x => x.Stream2FieldTypes[i].s2fIsRequired)%>
Field Type ID": <%: Html.EditorFor(x => x.Stream2FieldTypes[i].FieldTypeID, new { style="width:20px;" })%>
Stream ID: <%: Html.EditorFor(x => x.Stream2FieldTypes[i].StreamID) %>
</div>
<% } %>
Why isn’t the default model binder in mvc correctly binding the nested collection?
I would recommend you using POCO view models instead of those cluttered model classes. They are not adapted to the view and are difficult to work with. Trying to bind to LINQ specific collections like
EntitySet<T>is not a good idea. This being using an editor template might actually work but even if this works bear mind that it should be a temporary solution until you introduce proper view models.In your main view replace the loop with this:
and then add a strongly typed partial view in
~/Views/Home/EditorTemplates/Stream2FieldTypes.ascx:Normally this should take care of generating correct input names, but to avoid people taking this as a good example: I repeat once again use proper view models.