多态性实体框架 [英] Polymorphism in Entity Framework

查看:95
本文介绍了多态性实体框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体的类(的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 =htt​​p://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; D​​IV 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; D​​IV ='无'类=divcard&GT;
            &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryMonth)
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =主编场&GT;
                @ Html.EditorFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryMonth)
                @ Html.ValidationMessageFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryMonth)
            &LT; / DIV&GT;             &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryYear)
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =主编场&GT;
                @ Html.EditorFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryYear)
                @ Html.ValidationMessageFor(型号=&GT;((信用卡式)model.billingDetail).ExpiryYear)
            &LT; / DIV&GT;
        &LT; / DIV&GT;        &LT; D​​IV ='无'类=divbank&GT;
            &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT;((的BankAccount)model.billingDetail).BankName)
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =主编场&GT;
                @ Html.EditorFor(型号=&GT;((的BankAccount)model.billingDetail).BankName)
                @ Html.ValidationMessageFor(型号=&GT;((的BankAccount)model.billingDetail).BankName)
            &LT; / DIV&GT;             &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT;((的BankAccount)model.billingDetail).Swift)
            &LT; / DIV&GT;
            &LT; D​​IV 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; D​​IV&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:

http://weblogs.asp.net/manavi/archive/2010/12/28/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt.aspx

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆