Asp.net mvc 实体框架中的多态性
具体的类(Asp.net mvc 实体框架中的多态性,asp.net-mvc,entity-framework,razor,dynamic,polymorphism,Asp.net Mvc,Entity Framework,Razor,Dynamic,Polymorphism,具体的类(银行账户和信用卡)在控制器上不可见 我被这个问题缠住了 我正在使用这个网站上的例子: 视图 CreateUser: 如果选择了信用卡,它应该与用户类关联 图表 代码 用户控制器: [HttpPost] public ActionResult Create(User user)//The Watch above came from this user instance { if (ModelState.IsValid) {
银行账户
和信用卡
)在控制器上不可见
我被这个问题缠住了
我正在使用这个网站上的例子:
视图
CreateUser
:
如果选择了信用卡
,它应该与用户
类关联
图表
代码
用户控制器:
[HttpPost]
public ActionResult Create(User user)//The Watch above came from this user instance
{
if (ModelState.IsValid)
{
context.User.Add(user);
context.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.PossibleBillingDetail = context.BillingDetail;
return View(user);
}
User\\u CreateOrEdit.cshtml
:
@model TPTMVC.Models.User
@using TPTMVC.Models;
<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.5.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.divbank').hide();
$('input[type=radio]').live('change', function () { updateweather(); });
});
function updateweather() {
//alert();
if ($('input[type=radio]:checked').val() == 'Bank') {
$('.divcard').fadeOut(1000);
$('.divcard').hide();
$('.divbank').fadeIn(1000);
}
else {
$('.divbank').fadeOut(1000);
$('.divbank').hide();
$('.divcard').fadeIn(1000);
}
}
</script>
<div id="json"></div>
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
@Html.Partial("_CreateOrEdit", Model)
<div ='none' class="divcard">
<div class="editor-label">
@Html.LabelFor(model => ((CreditCard)model.billingDetail).ExpiryMonth)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((CreditCard)model.billingDetail).ExpiryMonth)
@Html.ValidationMessageFor(model => ((CreditCard)model.billingDetail).ExpiryMonth)
</div>
<div class="editor-label">
@Html.LabelFor(model => ((CreditCard)model.billingDetail).ExpiryYear)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((CreditCard)model.billingDetail).ExpiryYear)
@Html.ValidationMessageFor(model => ((CreditCard)model.billingDetail).ExpiryYear)
</div>
</div>
<div='none' class="divbank">
<div class="editor-label">
@Html.LabelFor(model => ((BankAccount)model.billingDetail).BankName)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((BankAccount)model.billingDetail).BankName)
@Html.ValidationMessageFor(model => ((BankAccount)model.billingDetail).BankName)
</div>
<div class="editor-label">
@Html.LabelFor(model => ((BankAccount)model.billingDetail).Swift)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((BankAccount)model.billingDetail).Swift)
@Html.ValidationMessageFor(model => ((BankAccount)model.billingDetail).Swift)
</div>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
User\Create.cshtml
:
@model TPTMVC.Models.User
@using TPTMVC.Models;
<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.5.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.divbank').hide();
$('input[type=radio]').live('change', function () { updateweather(); });
});
function updateweather() {
//alert();
if ($('input[type=radio]:checked').val() == 'Bank') {
$('.divcard').fadeOut(1000);
$('.divcard').hide();
$('.divbank').fadeIn(1000);
}
else {
$('.divbank').fadeOut(1000);
$('.divbank').hide();
$('.divcard').fadeIn(1000);
}
}
</script>
<div id="json"></div>
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
@Html.Partial("_CreateOrEdit", Model)
<div ='none' class="divcard">
<div class="editor-label">
@Html.LabelFor(model => ((CreditCard)model.billingDetail).ExpiryMonth)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((CreditCard)model.billingDetail).ExpiryMonth)
@Html.ValidationMessageFor(model => ((CreditCard)model.billingDetail).ExpiryMonth)
</div>
<div class="editor-label">
@Html.LabelFor(model => ((CreditCard)model.billingDetail).ExpiryYear)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((CreditCard)model.billingDetail).ExpiryYear)
@Html.ValidationMessageFor(model => ((CreditCard)model.billingDetail).ExpiryYear)
</div>
</div>
<div='none' class="divbank">
<div class="editor-label">
@Html.LabelFor(model => ((BankAccount)model.billingDetail).BankName)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((BankAccount)model.billingDetail).BankName)
@Html.ValidationMessageFor(model => ((BankAccount)model.billingDetail).BankName)
</div>
<div class="editor-label">
@Html.LabelFor(model => ((BankAccount)model.billingDetail).Swift)
</div>
<div class="editor-field">
@Html.EditorFor(model => ((BankAccount)model.billingDetail).Swift)
@Html.ValidationMessageFor(model => ((BankAccount)model.billingDetail).Swift)
</div>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
问题
单击“创建”按钮时,我得到以下结果:
我选择了一张信用卡
,但结果是BillingDetail
。我试着做一个演员,但我犯了一个错误,正如你所看到的
:(
为什么只有BillingDetail
出现在UserController
上
我的第一个解决方案
我认为这里有几件事不对:
BillingDetail
,一个c#类,转换为模型供您查看,然后随表单提交一起返回。据我所知,只能返回普通数据和表单字段在表单提交中。您可以让视图模型包含其他视图模型和具体类,但只能返回普通字段和包含普通字段的视图模型- 为
和信用卡
创建两个单独的视图模型,每个视图模型都有各自的属性。(您应该对银行账户
对象执行相同的操作,以便遵守SoC)用户
- 使用模型填充视图,使用两个新视图模型代替
BillingDetail
- 提交表单时,将单选按钮用作控制器中的条件,以确定用户选择的付款类型,然后创建相应的对象,将视图模型属性映射到具体对象,将其添加到用户,然后保存
ViewBag.PossibleBillingDetail = context.BillingDetail;
这还包括BankAccount
s,因此一些BillingDetail
对象不能强制转换为CreditCard
将线路更换为
ViewBag.PossibleBillingDetail = context.BillingDetail.OfType<CreditCard>();
ViewBag.PossibleBillingDetail=context.BillingDetail.OfType();
您正在将一个用户
对象传递给您的视图。该对象具有到账单详细信息
的导航属性,可以是信用卡
或银行账户
。您可以在视图(信用卡)模型
和(银行账户)中按此方式进行转换模型
。创建时它会工作,因为您正在强制转换为null的实例,但如果您有非null实例,则会导致运行时错误,因为其中一个强制转换将失败
若要修复此问题,您可以使用模型作为信用卡
和模型作为银行帐户
,然后在呈现相应编辑器之前检查它们是否为空。但是,您需要确定当您的用户想要更改付款方式时该怎么办
当表单返回到控制器时,由于您的Create
方法签名采用了User
参数,因此默认的ModelBinder
知道它应该实例化User
。它很有能力做到这一点,但它无法解决如何处理FormCollect中出现的值与账单详细信息相关的ion
对于继承,您不能依赖默认的ModelBinder
。您需要找出最适合您的方法。以下是一些我发现很有用的参考资料:
-但看看这里的所有其他解决方案
下面是我的项目中的一些示例代码,可以让您了解:
public ActionResult CreateOrEdit(FormCollection values)
{
//The FormCollection is either a Property or a Block
BaseProperty model;
if (values["PropertyTypeID"] != null)
{
//it must be a Property!
Property property = new Property();
TryUpdateModel(property);
_Uow.PropertyRepository.InsertOrUpdate(property);
model = property;
}
else
{
Block block = new Block();
TryUpdateModel(block);
_Uow.BlockRepository.InsertOrUpdate(block);
model = block;
}
//etc....
你能添加你的信用卡类别定义吗?道格,我添加了信用卡类别。格特·阿诺德,在做任何事情之前,我想感谢你的帮助,但你的建议不会改变结果。:(第1项说“不应该”,所以它是正确的,但不严格相关,因为它不会解决问题……第2项说“您不能在网页数据中返回具体的服务器端对象".这是严格正确的,但是默认的ModelBinder
使它看起来像是你可以…所以你可以说一个…第3项击中了要害,最后一个要点是你的解决方案…现在你需要决定在哪里创建相应的对象。自定义模型绑定器还是在控制器中?是的,第1点更像是一个最佳实践,这是对他未来问题的先发制人的解决方法!我建议他使用AutoMapper或类似的对象创建。马特·福克斯·邓肯,你觉得我的第一个解决方案怎么样?是你的解决方案吗?科林,你觉得我的第一个解决方案怎么样?@Eduardoxvii。看起来不错。我会更改“收音机”的名称参数设置为更有意义的参数-例如“PaymentMethod”。它有效吗?
public ActionResult CreateOrEdit(FormCollection values)
{
//The FormCollection is either a Property or a Block
BaseProperty model;
if (values["PropertyTypeID"] != null)
{
//it must be a Property!
Property property = new Property();
TryUpdateModel(property);
_Uow.PropertyRepository.InsertOrUpdate(property);
model = property;
}
else
{
Block block = new Block();
TryUpdateModel(block);
_Uow.BlockRepository.InsertOrUpdate(block);
model = block;
}
//etc....