This is a ModelBinder to use with the new ASP.NET MVC framework RC1. 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 RC1
Usage
Add the LLBLGenModelBinder.cs to your project
In the Global.asax.cs, add this to the Application_Start():
ModelBinders.Binders.DefaultBinder = new 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:
The RC1 release behaviour changed from the beta.
The beta looked for a .index property and looped through them to fill the collection
RC1 ONLY processes for sequential indexes starting with 0.
I have implemented the beta behaviour if an index field exists, otherwise it passes through to the RC1 method.
If you do not want this behaviour at all, remove the region "handle Beta style collections with .index"
RC1 behaviour: Name your fields company.Contacts[0].FieldName, counting up from 0
<% for (int i=0;i<Model.Contacts.Count;i++)
ContactEntity contact = Model.Contacts[i]; {%>
<tr>
<td>Contacts.ContactId</td>
<td><%= Html.TextBox("company.Contacts[" + i + "].ContactId", contact.ContactId)%></td>
</tr>
<tr>
<td>Contacts.FirstName</td>
<td><%= Html.TextBox("company.Contacts[" + i + "].FirstName", contact.FirstName)%></td>
</tr>
<tr>
<td>Contacts.LastName</td>
<td><%= Html.TextBox("company.Contacts[" + i + "].LastName", contact.LastName)%></td>
</tr>
<% } %>
To add, you need to add a new set of fields numbered one higher.
Beta behaviour: looks for a field (.index) that holds the index values to iterate:
<% foreach (ContactEntity contact in 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);
}
}
Attachments
Filename |
File size |
Added on |
Approval |
LLBLGenModelBinder.cs
|
15,261 |
29-Jan-2009 23:39.12 |
Approved |