I am interested in the best way to deal with foreign key relationships when using ASP.NET MVC and the Entity Framework.
I am currently using a ViewModel to output a create and edit page (using a partial), but things don't work too well when I get to posting the data back.
Before I validate my model I use the posted value from the select list to look up the foreign object and assign it to my model, but when I use UpdateModel
on the edit the references end up being null, I am guessing because it is not able to bind that property correctly.
How do people normally deal with this issue? Using a ViewModel to populate my dropdowns seems straigtforward enough, but I must be missing something when it comes to the edit. Do people normally create their own binder to get around this issue?
I have tried using both strong typing and the FormCollection
.
ViewModel:
public class ReportViewModel
{
public Report Report { get; set; }
public SelectList ReportDeliveryMethods { get; set; }
public string ReportDeliveryMethod { get; set; }
public SelectList ReportReceivers { get; set; }
public string ReportReceiver { get; set; }
public SelectList PermitTypes { get; set; }
public string PermitType { get; set; }
}
Controller:
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
Report report;
try
{
report = repository.GetReport(id);
// Convert ReportDeliveryMethod to Object Reference
if (!string.IsNullOrEmpty(collection["ReportDeliveryMethod"]))
{
int reportDeliveryMethodId = 0;
if (int.TryParse(collection["ReportDeliveryMethod"], out reportDeliveryMethodId))
{
report.ReportDeliveryMethod = repository.GetReportDeliveryMethod(reportDeliveryMethodId);
}
}
// Convert ReportReceiver to Object Reference
if (!string.IsNullOrEmpty(collection["ReportReceiver"]))
{
int reportReceiverId = 0;
if (int.TryParse(collection["ReportReceiver"], out reportReceiverId))
{
report.ReportReceiver = repository.GetReportReceiver(reportReceiverId);
}
}
// Convert PermitType to Object Reference
if (!string.IsNullOrEmpty(collection["PermitType"]))
{
int permitTypeId = 0;
if (int.TryParse(collection["PermitType"], out permitTypeId))
{
report.PermitType = repository.GetPermitType(permitTypeId);
}
}
if (ModelState.IsValid)
{
UpdateModel(report);
repository.Save();
return RedirectToAction("Index");
}
else
{
return View();
}
}
catch (Exception ex)
{
return View();
}
}
Form:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<PermitLookup.Models.ReportViewModel>" %>
<% using (Html.BeginForm())
{%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.ShareName) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Report.ShareName) %>
<%: Html.ValidationMessageFor(model => model.Report.ShareName)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.Description) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Report.Description)%>
<%: Html.ValidationMessageFor(model => model.Report.Description)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.Frequency)%>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Report.Frequency)%>
<%: Ht开发者_开发百科ml.ValidationMessageFor(model => model.Report.Frequency)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.SendTime)%>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Report.SendTime)%>
<%: Html.ValidationMessageFor(model => model.Report.SendTime)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.ReportDeliveryMethod)%>
</div>
<div class="editor-field">
<%=Html.DropDownListFor(model => model.ReportDeliveryMethod, Model.ReportDeliveryMethods)%>
<%: Html.ValidationMessageFor(model => model.Report.ReportDeliveryMethod)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.ReportReceiver)%>
</div>
<div class="editor-field">
<%=Html.DropDownListFor(model => model.ReportReceiver, Model.ReportReceivers)%>
<%: Html.ValidationMessageFor(model => model.Report.ReportReceiver)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Report.PermitType)%>
</div>
<div class="editor-field">
<%=Html.DropDownListFor(model => model.PermitType, Model.PermitTypes)%>
<%: Html.ValidationMessageFor(model => model.Report.PermitType)%>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
Let's consider ReportDeliveryMethod
. In your view model, it's a string
. On your Report
object, it's a ReportDeliveryMethod
type. Since a string
can't be implicitly cast to a ReportDeliveryMethod
, UpdateModel
won't bind it.
So what are your choices?
- Map manually, like you're doing now.
- Bind the ID, rather than the object reference. EF 4 supports FK associations. You could put
ReportDeliveryMethodId
in your view model instead ofReportDeliveryMethod
.
精彩评论