多态性实体框架 [英] Polymorphism in Entity Framework
问题描述
具体的类(的BankAccount
和信用卡式
)不在控制器可见。
我坚持这个问题。
我使用本网站的例子:
<一个href=\"http://weblogs.asp.net/manavi/archive/2010/12/28/inheritance-mapping-strategies-with-entity-framework-$c$c-first-ctp5-part-2-table-per-type-tpt.aspx\" rel=\"nofollow\">http://weblogs.asp.net/manavi/archive/2010/12/28/inheritance-mapping-strategies-with-entity-framework-$c$c-first-ctp5-part-2-table-per-type-tpt.aspx
视图
的 CREATEUSER
:
如果在信用卡式
选择应该关联到用户
类。
该图
在code
UserController中
[HttpPost]
公众的ActionResult创建(用户用户)//手表上面从这个用户实例来
{
如果(ModelState.IsValid)
{ context.User.Add(用户);
context.SaveChanges();
返回RedirectToAction(「指数」);
} ViewBag.PossibleBillingDetail = context.BillingDetail;
返回查看(用户);
}
用户\\ _CreateOrEdit.cshtml
:
用户\\ Create.cshtml
:
@model TPTMVC.Models.User
@using TPTMVC.Models;&LT;脚本SRC =http://ajax.microsoft.com/ajax/jQuery/jquery-1.5.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
&LT;脚本类型=文/ JavaScript的&GT; $(文件)。就绪(函数(){
$('。divbank')隐藏()。
$('输入[类型=无线电]')生活('变',函数(){updateweather();});
}); 功能updateweather(){
//警报();
如果($('输入[类型=电台]:勾选)。VAL()=='银行'){
$('。divcard')淡出(1000)。
$('。divcard')隐藏()。
$('。divbank')淡入(1000)。
}
其他{
$('。divbank')淡出(1000)。
$('。divbank')隐藏()。
$('。divcard')淡入(1000)。
} }
&LT; / SCRIPT&GT;
&LT; DIV ID =json的&GT;&LT; / DIV&GT;@ {
ViewBag.Title =创建;
}&LT; H2&GT;创建&LT; / H&GT;@using(Html.BeginForm())
{
@ Html.ValidationSummary(真)
&LT;&字段集GT;
&LT;传奇&gt;用户&LT; /传说&GT; @ Html.Partial(_ CreateOrEdit模型) &LT; DIV ='无'类=divcard&GT;
&LT; DIV CLASS =编辑标记&GT;
@ Html.LabelFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryMonth)
&LT; / DIV&GT;
&LT; DIV CLASS =主编场&GT;
@ Html.EditorFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryMonth)
@ Html.ValidationMessageFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryMonth)
&LT; / DIV&GT; &LT; DIV CLASS =编辑标记&GT;
@ Html.LabelFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryYear)
&LT; / DIV&GT;
&LT; DIV CLASS =主编场&GT;
@ Html.EditorFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryYear)
@ Html.ValidationMessageFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryYear)
&LT; / DIV&GT;
&LT; / DIV&GT; &LT; DIV ='无'类=divbank&GT;
&LT; DIV CLASS =编辑标记&GT;
@ Html.LabelFor(型号=&GT;((的BankAccount)model.billingDetail).BankName)
&LT; / DIV&GT;
&LT; DIV CLASS =主编场&GT;
@ Html.EditorFor(型号=&GT;((的BankAccount)model.billingDetail).BankName)
@ Html.ValidationMessageFor(型号=&GT;((的BankAccount)model.billingDetail).BankName)
&LT; / DIV&GT; &LT; DIV CLASS =编辑标记&GT;
@ Html.LabelFor(型号=&GT;((的BankAccount)model.billingDetail).Swift)
&LT; / DIV&GT;
&LT; DIV CLASS =主编场&GT;
@ Html.EditorFor(型号=&GT;((的BankAccount)model.billingDetail).Swift)
@ Html.ValidationMessageFor(型号=&GT;((的BankAccount)model.billingDetail).Swift)
&LT; / DIV&GT;
&LT; / DIV&GT;
&所述p为H.;
&LT;输入类型=提交值=创建/&GT;
&所述; / P&GT;
&LT; /字段集&GT;
}&LT; DIV&GT;
@ Html.ActionLink(返回目录,索引)
&LT; / DIV&GT;
类code:
命名空间TPTMVC.Models {
公共类BillingDetail
{
[键]
[ForeignKey的(用户)]
公众诠释用户名{搞定;组; }
公共字符串所有者获得{;组; }
公共弦数{搞定;组; }
公共虚拟用户用户{搞定;组; }
}}命名空间TPTMVC.Models {
公共类用户
{
公众诠释用户ID {搞定;组; }
公共字符串名字{获得;组; }
公共字符串名字{获得;组; } 公共虚拟BillingDetail billingDetail {搞定;组; }
}}
命名空间TPTMVC.Models {
[表(BankAccounts)]
公共类的BankAccount:BillingDetail
{
公共字符串BANKNAME {搞定;组; }
公共字符串斯威夫特{搞定;组; }
}}
命名空间TPTMVC.Models {
[表(CreditCards)]
公共类信用卡式:BillingDetail
{
公众诠释CardType {搞定;组; }
公共字符串ExpiryMonth {搞定;组; }
公共字符串ExpiryYear {搞定;组; }
}}
问题
当我点击创建按钮,我得到这样的结果:
我选择了一个信用卡式
但结果却是 BillingDetail
。我试图让铸造,但我得到了一个错误,因为你可以看到。
(
为什么只有 BillingDetail
出现在 UserController的
?
我的第一个解决方案
[HttpPost]
公众的ActionResult创建(用户用户,信用卡式卡,银行的BankAccount,字符串电台)
{
//字符串睾丸=的FormCollection [电台];
如果(ModelState.IsValid)
{
开关(单选)
{
案CredCard:
user.billingDetail =卡;
打破;
案银行:
user.billingDetail =银行;
打破;
}
context.User.Add(用户);
context.SaveChanges();
返回RedirectToAction(「指数」);
} ViewBag.PossibleBillingDetail = context.BillingDetail;
返回查看(用户);
}
您是通过一个用户
对象视图。这有一个导航属性到 BillingDetail
可以是一个信用卡式
或的BankAccount
。您可以在视图(信用卡式)模型
和(的BankAccount)模型
铸像这样。当你的创造,因为你投实例为空,将工作,但它会导致运行时错误,当你有一个非空的情况下,因为强制转换的人会失败。
要解决这个问题,你可以使用模型作为信用卡式
和模型的BankAccount
然后检查他们是不是null之前呈现适当的编辑器。但是,你需要当你的用户想改变付款方式制定出该怎么做。
当的形式返回到控制器,因为你的创建
方法签名需要一个用户
参数,则默认 ModelBinder的
知道它应该实例化一个用户
。这是很能说,但它不能制定出如何处理出现的数值做的FormCollection
,涉及到 BillingDetail
。
通过继承您不能依赖于默认 ModelBinder的
。你需要制定出最适合你。下面是一些参考资料,我发现有用的:
的获取ModelBinding 的理解
<一个href=\"http://www.agileatwork.com/inheritance-is-evil-the-story-of-the-epic-fail-of-dataannotationsmodelbinder/\"相对=nofollow>自定义模型粘合剂 - 一个人的意见
我去解决方案 - !不过看在所有其他解决方案在这里也
下面是从我的项目的一些例子code,应该给你一个想法:
公众的ActionResult CreateOrEdit(的FormCollection值)
{
//本的FormCollection或者是物业或块
BaseProperty模型;
如果(值[PropertyTypeID]!= NULL)
{
//它必须是一个属性!
属性属性=新的属性();
TryUpdateModel(财产);
_Uow.PropertyRepository.InsertOrUpdate(财产);
模型=财产;
}
其他
{
一块块=新的块();
TryUpdateModel(块);
_Uow.BlockRepository.InsertOrUpdate(块);
模型=块;
}
//等等....
The concrete classes (BankAccount
and CreditCard
) are not visible on controller.
I'm stuck with this issue.
I'm using the example from this site:
The view
The CreateUser
:
If the CreditCard
was selected it should be associated to the User
class.
The diagram
The code
UserController:
[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\_CreateOrEdit.cshtml
:
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>
Classes code:
namespace TPTMVC.Models{
public class BillingDetail
{
[Key]
[ForeignKey("user")]
public int UserID { get; set; }
public string Owner { get; set; }
public string Number { get; set; }
public virtual User user { get; set; }
}}
namespace TPTMVC.Models{
public class User
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual BillingDetail billingDetail { get; set; }
}}
namespace TPTMVC.Models{
[Table("BankAccounts")]
public class BankAccount:BillingDetail
{
public string BankName { get; set; }
public string Swift { get; set; }
}}
namespace TPTMVC.Models{
[Table("CreditCards")]
public class CreditCard:BillingDetail
{
public int CardType { get; set; }
public string ExpiryMonth { get; set; }
public string ExpiryYear { get; set; }
}}
The problem
When I click the create button, I get this result:
I selected a CreditCard
but the result was BillingDetail
. I tried to make a casting but I got a error, as you can see.
:(
Why only BillingDetail
appear on UserController
?
My first solution
[HttpPost]
public ActionResult Create(User user, CreditCard card, BankAccount bank, String Radio)
{
//String teste=formCollection["Radio"];
if (ModelState.IsValid)
{
switch (Radio)
{
case "CredCard":
user.billingDetail = card;
break;
case "Bank":
user.billingDetail = bank;
break;
}
context.User.Add(user);
context.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.PossibleBillingDetail = context.BillingDetail;
return View(user);
}
You are passing a User
object to your View. This has a navigation property to BillingDetail
which can be a CreditCard
or a BankAccount
. You cast it like this in the View (CreditCard)model
and (BankAccount)model
. It will work when your creating because you are casting an instance that is null, but it will cause a run-time error when you have a non-null instance because one of the casts will fail.
To fix that you can use model as CreditCard
and model as BankAccount
then check they are not null before you render the appropriate editors. But you'll need to work out what to do when your user wants to change the payment method.
When the form is returned to the controller, because your Create
method signature takes a User
parameter, the default ModelBinder
knows that it should instantiate a User
. It is quite capable of that, but it is not able to work out what to do with the values that appear in the FormCollection
that relate to the BillingDetail
.
With inheritance you can't rely on the default ModelBinder
. You need to work out what suits you best. Here's some references I found useful:
Get an understanding of ModelBinding
Custom model binders - one person's opinion
The solution I went with - but look at all the other solutions here too!
Here's some example code from my project that should give you an idea:
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....
这篇关于多态性实体框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!