Not sure if this is the right forum?
Here is a ModelBinder to use with the new ASP.NET MVC framework (tested with the Beta release, all bets are off when RC1 comes out). This will automatically create and populdate LLBLGen objects from form post, query string and route data. Works with both SelfServicing and Adapter.
An overview of Model Binding in ASP.NET MVC can be found here: http://weblogs.asp.net/scottgu/archive/2008/09/02/asp-net-mvc-preview-5-and-form-posting-scenarios.aspx and here: http://weblogs.asp.net/scottgu/archive/2008/10/16/asp-net-mvc-beta-released.aspx#three
This implementation inherits from the provided DefaultModelBinder and defers most of the work to it. For non LLBLGen entities, they just pass through to the default implementation. This code is to help set the primary keys and stop infinite recursive Parent-Child-Parent calls.
Requirements
- LLBLGen Pro v2.6
- .NET 3.5 SP1
- ASP.NET MVC Beta
Usage
Add the LLBLGenModelBinder.cs to your project
In the Global.asax.cs, add this to the Application_Start():
ModelBinders.DefaultBinder = new MvcHelpers.LLBLGenModelBinder();
You will be able to write code like this and have the entities automatically populated from the request
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(CompanyEntity company)
{
if (ModelState.IsValid)
{
company.Save(true);
return RedirectToAction("Edit", new { id = company.CompanyId });
}
else
{
return View(company);
}
}
How it works
In order for the Model Binding to find the correct fields, they need to be named correctly.
For the top level object, the take the form parameterName.Field so: <%= Html.TextBox("company.CompanyId", ViewData.Model.CompanyId)%>
For 1-to-1 objects, they look like <%= Html.TextBox("company.NormalAddress.Address", ViewData.Model.NormalAddress.Address)%>
For 1-to-many it gets a little more complex (note: this is the MVC implementation and may change with the RC release)
For the many side, it looks for a field that holds the index numbers to iterate, then looks for named form post fields:
<% foreach (ContactEntity contact in ViewData.Model.Contacts) {%>
<tr>
<td>Contacts.index</td>
<td><%= Html.TextBox("company.Contacts.index", contact.ContactId)%></td>
</tr>
<tr>
<td>Contacts.ContactId</td>
<td><%= Html.TextBox("company.Contacts[" + contact.ContactId + "].ContactId", contact.ContactId)%></td>
</tr>
<tr>
<td>Contacts.FirstName</td>
<td><%= Html.TextBox("company.Contacts[" + contact.ContactId + "].FirstName", contact.FirstName)%></td>
</tr>
<tr>
<td>Contacts.LastName</td>
<td><%= Html.TextBox("company.Contacts[" + contact.ContactId + "].LastName", contact.LastName)%></td>
</tr>
<% } %>
if you want to add a new object, create any unique index:
<%= Html.TextBox("company.Contacts.index", -1)%>
<%= Html.TextBox("company.Contacts[-1].ContactId", 0)%>
<%= Html.TextBox("company.Contacts[-1].FirstName")%>
NOTES
The Model Binder sets IsNew if a primary key field is set to a meaningful value (for ints > 0, strings not blank, etc.). You can change this behaviour by providing your own form field (i.e. company.IsNew) AND removing the "IsNew" from the list of excluded fields in the LLBLGenModelBinder
The binder only follows relations where the entity is on the PK Side, this keeps circular references from spinning out.
This process "creates" child objects, it does not "syncronize" child objects. It can syncronize objects, but you need to use the UpdateModel method to manually walk the child elements of 1-to-many. In this case, DO NOT output the .index form element because they will be in the child collection twice.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit2(int id)
{
CompanyEntity company = new CompanyEntity(id);
UpdateModel(company, "company");
foreach (ContactEntity contact in company.Contacts)
{
UpdateModel(contact, "company.Contacts[" + contact.ContactId + "]");
}
if (ModelState.IsValid)
{
company.Save(true);
return RedirectToAction("Edit", new { id = company.CompanyId });
}
else
{
return View(company);
}
}
Thanks
Brian Chance