3

具象クラス (BankAccountおよびCreditCard) はコントローラーには表示されません。

私はこの問題で立ち往生しています。

このサイトの例を使用しています:

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

景色

CreateUser:_

が選択されている場合は、クラスCreditCardに関連付ける必要があります。User

ユーザーを作成

ダイアグラム

クラス図

コード

ユーザーコントローラー:

    [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>

クラスコード:

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; }
}}

問題

作成ボタンをクリックすると、次の結果が得られます。

時計

を選択しましたCreditCardが、結果は でしたBillingDetail。キャストを作成しようとしましたが、ご覧のとおりエラーが発生しました。

:(

にのみBillingDetail表示されるのはなぜUserControllerですか?

私の最初の解決策

[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);
        }
4

3 に答える 3

2

Userビューにオブジェクトを渡しています。これには、またはのナビゲーション プロパティがBillingDetailあります。Viewとでこのようにキャストします。null のインスタンスをキャストしているため、作成時には機能しますが、キャストの 1 つが失敗するため、null 以外のインスタンスがあると実行時エラーが発生します。CreditCardBankAccount(CreditCard)model(BankAccount)model

これを修正するには、適切なエディターをレンダリングする前に使用model as CreditCardして、それらが null でないことを確認します。model as BankAccountただし、ユーザーが支払い方法を変更したい場合はどうすればよいかを考える必要があります。

フォームがコントローラーに返されると、Createメソッド シグネチャがUserパラメーターを受け取るため、デフォルトModelBinderではUser. FormCollectionそれはかなり可能ですが、に関連する に表示される値をどうするかを理解することはできませんBillingDetail

継承では、デフォルトに依存することはできませんModelBinder。自分に一番合ったものを見つける必要があります。ここに私が有用だと思ったいくつかの参考文献があります:

ModelBinding を理解する

カスタムモデルバインダー - 一人の意見

私が行った解決策- しかし、他のすべての解決策もここで見てください!

私のプロジェクトのコード例をいくつか示します。

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....
于 2013-10-18T13:31:38.297 に答える
1

ここにはいくつかの間違いがあると思います:

  1. 懸念事項の分離を順守していません。提供したモデル ダイアグラムがエンティティ用である場合、それらをフロントエンド モデルとして使用するべきではありません。データ レイヤーとビュー レイヤーは別々のモデルを持つ必要があります。これにより、データの設計方法とユーザーが操作する方法を切り離すことができます。
  2. SO ユーザーは、私が間違っている場合は修正してください。ただし、Web ページ データで具体的なサーバー側オブジェクトを返すことはできません。この場合BillingDetail、ac# クラスをビューのモデルにキャストし、フォーム送信でそれを返そうとしています。私の知る限り、フォーム送信ではプレーン データとフォーム フィールドのみを返すことができます。ビュー モデルに他のビュー モデルと具象クラスを含めることはできますが、プレーン フィールドとプレーン フィールドを含むビュー モデルのみを返すことができます。
  3. 基本クラスを派生クラスにキャストしようとしています。これは、派生クラスを基本クラスとして渡し、それを別の場所に再キャストした場合に可能ですが、純粋な基本クラスを取得してより具体的なオブジェクトに変換することはできません。四角形を四角形にしようとしているようなものです。

解決策として、これを行う必要があります:

  • との 2 つの個別のビュー モデルを作成CreditCardBankAccount、それぞれにそれぞれのプロパティを設定します。User( SoCに準拠するように、オブジェクトに対して同じことを行う必要があります)
  • の代わりに 2 つの新しいビュー モデルを使用して、モデルを使用してビューを作成しますBillingDetail
  • フォームが送信されたら、ラジオ ボタンをコントローラーの条件として使用して、ユーザーが選択した支払いの種類を決定し、それぞれのオブジェクトを作成し、ビュー モデルのプロパティを具体的なオブジェクトにマップし、それをユーザーに追加して、保存します。 .
于 2013-10-17T20:23:16.773 に答える