この DefaultModelBinder について数日間読もうとしていますが、まだ非常に混乱しています。MVC 4 & EF 5 TablePerHiearchy 構造を使用しています。
私の問題は、Resource の基本クラスがあることです。
public class Resource : PocoBaseModel
{
private int _resourceID;
private string _title;
private string _description;
//public accessors
}
サブクラス (DVD、EBook、Book など) を持つ
public class DVD : Resource
{
private string _actors;
//more fields and public accessors
}
コントローラー コードでカスタム ModelBinder を使用している
[HttpPost]
public ActionResult Create([ModelBinder(typeof(ResourceModelBinder))] Resource resource)
{
//controller code
}
public class ResourceModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var type = controllerContext.HttpContext.Request.Form["DiscriminatorValue"];
bindingContext.ModelName = type;
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, resourceTypeMap[type]);
return base.BindModel(controllerContext, bindingContext);
}
static Dictionary<string, Type> resourceTypeMap = new Dictionary<string, Type>
{
{"Resource", typeof(Resource)},
{"Book", typeof(Book)},
{"DVD", typeof(DVD)},
{"EBook", typeof(EBook)},
{"Hardware", typeof(Hardware)},
{"Software", typeof(Software)}
};
}
ビューをリソース (DVD、ブック、またはその他のタイプとしてキャスト) に渡すことができるように
@model Models.Resource
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm("Create", "Admin", null, FormMethod.Post, null))
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Resource</legend>
@Html.HiddenFor(model => model.ResourceID)
@Html.HiddenFor(model => model.ResourceTypeID)
@Html.HiddenFor(model => model.Committed)
@Html.Partial("_CreateOrEdit", Model)
<p>
<input type="submit" value="Create"/>
</p>
</fieldset>
}
部分ビュー内のスイッチで発生する派生プロパティに基づいてバインドします。
@using Models.ViewModels;
@using Models.ResourceTypes;
@using Helper;
@model Models.Resource
@Html.HiddenFor(model => Model.DiscriminatorValue);
<table cellspacing="2" cellpadding="2" border="0">
@{
string type = Model.DiscriminatorValue;
switch (type)
{
case "Book":
Book book = (Book)Model;
<tr>
<td colspan="2">
<div class="editor-label" style="padding-top: 15px;">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Title, new { style = "width: 750px; height: 65px;" })
@Html.ValidationMessageFor(model => model.Title)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Edition)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => book.Edition, new { style = "width: 150px;" })
@Html.ValidationMessageFor(model => book.Edition)
</div>
</td>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Author)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.Author)
@Html.ValidationMessageFor(model => book.Author)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.Pages)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => book.Pages, new { style = "width: 75px;" })
@Html.ValidationMessageFor(model => book.Pages)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="editor-label">
@Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Description, new { style = "width: 750px; height: 105px;" })
@Html.ValidationMessageFor(model => model.Description)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="editor-label">
@Html.LabelFor(model => model.AdminNote)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.AdminNote, new { style = "width: 750px; height: 105px;" })
@Html.ValidationMessageFor(model => model.AdminNote)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@{ int copies = Model == null ? 1 : Model.Copies; }
@Html.LabelFor(model => model.Copies)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Copies, new { style = "width: 75px;", @Value = copies.ToString() })
@Html.ValidationMessageFor(model => model.Copies)
</div>
</td>
</tr>
<tr>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.ISBN10)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.ISBN10)
@Html.ValidationMessageFor(model => book.ISBN10)
</div>
</td>
<td>
<div class="editor-label">
@Html.LabelFor(model => book.ISBN13)
</div>
<div class="editor-field">
@Html.EditorFor(model => book.ISBN13)
@Html.ValidationMessageFor(model => book.ISBN13)
</div>
</td>
</tr>
break;
私の最初の問題は、フォームを投稿したときに、キャストされた型ではなくリソースとして返されることでした (そのため、すべての派生型プロパティが失われていました)。これが、ResourceModelBinder を作成した理由です。キャストされた型を正しくバインド/ポストバックするようになりましたが、Title、ResourceID、ResourceTypeID などのリソースの基本クラス プロパティはバインドしません。
基本リソースクラスのプロパティと派生型のプロパティを実際にバインドするために、私が欠けているものを理解するのを手伝ってくれる人はいますか?