web-dev-qa-db-ja.com

UpdateModel()を呼び出すときに、バインディングからプロパティをどのように除外しますか?

コントローラの編集アクションに送信されたビューモデルがあります。 ViewModelにはEntityObjectsへの参照が含まれています。 (そう、私はそれで大丈夫ですし、viewmodelのすべてのエンティティプロパティを複製する必要はありません)。

ビューモデルをインスタンス化してから、UpdateModelを呼び出します。プロパティが「null」であるというエラーが表示されます。これは関連モデルであるため問題ありません。モデルバインド中にバインドされないようにプロパティを除外しようとしています。これをデバッグすると、モデルバインダーがプロパティの値をnullに設定しようとしているエンティティが表示されます。

これが私の編集アクションです:

var model = new SimplifiedCompanyViewModel(id);

var excludeProperties = new string[] { 
   "Entity.RetainedEarningsAccount.AccountNo"
   ,"Property.DiscountEarnedAccount.ExpenseCodeValue"
   ,"Entity.EntityAlternate.EntityID"
   ,"Property.BankAccount.BankAccountID"
   ,"Entity.PLSummaryAccount.AccountNo"
   ,"Property.RefundBank.BankAccountID"
   ,"Company.Transmitter.TCC"
};

try
{
    UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);

    if (ModelState.IsValid)
    {
       //db.SaveChanges();
    }
       return RedirectToAction("Index");
}
catch
{
    return View(model);
}

「プレフィックス」の指定に関する他のいくつかの問題を確認しましたが、エンティティオブジェクトだけでなく、viewmodelインスタンスにバインドするように指示しているので、それは問題ではないと思います。

プロパティを正しく除外していますか?奇妙なことに、このアイテムでのみ発生するようです。私の実体に関連する払い戻し銀行が実際にはないという事実に問題があるのではないかと思います。しかし、私には他に存在しない関連項目があり、同じ問題は発生しません。

詳細...モデルはうまく設計されていないと言われました。

当社は銀行口座に関連しています。 Companyビューには、現在関連付けられているBankAccount.BankAccountIdが表示され、BankAccount.Keyを持つ非表示フィールドがあります。私はjQueryUIのオートコンプリート機能を使用してBankAccount.BankAccountIdを表示する銀行口座のドロップダウンを提供し、1つが選択されると、jQueryコードは非表示フィールドを変更して正しいキー値を設定します。したがって、これが投稿されたときに、現在の銀行口座BankAccountIDを変更したくないので、そのフィールドのバインドをスキップします。

モデルでBankAccountIdを除外すると、BankAccount編集ビューでは、バインドされないため、ユーザーはBankAccountIdを変更できません。これが貧弱なモデル設計をどのように示しているかわかりません。

18
PilotBob

ここでのもう1つのオプションは、ビューにこの属性を含めないだけで、バインドされません。はい-誰かがページ上で作成した場合でも、モデルインジェクションを利用できますが、別の方法です。 MVCのデフォルトテンプレートは、EditorForなどを個別のアイテムとして作成するので、それらを削除できます。これにより、EditorForModelで単一行ビューエディターを使用することはできなくなりますが、テンプレートはとにかくそれを生成しません。

編集(上記のコメントを追加)

DRYは通常、ビューモデルではなくロジックに適用されます。 1つのビュー= 1つのビューモデル。オートマッパーを使用して、それらの間を簡単にマッピングします。 Jimmy Bogardにはこのための優れた属性があり、ほぼ自動化されています。つまり、ビューモデルを作成し、たとえばCustomerエンティティをロードして、アクションメソッドで返します。次に、AutpMap属性はそれをViewModelに変換します。 lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models を参照してください

2

Exclude 属性の Bind プロパティを使用します。

[Bind(Exclude="Id,SomeOtherProperty")]
public class SimplifiedCompanyViewModel
{
    public int Id { get; set; }

    // ...
}

これはSystem.Web.Mvc名前空間の一部です。バインド時に除外するプロパティ名のコンマ区切りのリストが必要です。

また、UpdateModelの代わりにTryUpdateModelを使用することも検討してください。また、コンストラクターに引数として渡すことで、デフォルトのモデルバインダーにそれを理解させることもできます。

public ActionResult Create([Bind(Exclude="Id")]SimplifiedCompanyViewModel model)
{
    // ...
}
54
Dismissile

私が考え出した非常に単純な解決策。

 try
{
   UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
   ModelState.Remove("Entity.RetainedEarningsAccount.AccountNo");
   ModelState.Remove("Property.DiscountEarnedAccount.ExpenseCodeValue");
   ModelState.Remove("Entity.EntityAlternate.EntityID");
   ModelState.Remove("Property.BankAccount.BankAccountID");
   ModelState.Remove("Entity.PLSummaryAccount.AccountNo");
   ModelState.Remove("Property.RefundBank.BankAccountID");
   ModelState.Remove("ompany.Transmitter.TCC");

    if (ModelState.IsValid)
    {
       //db.SaveChanges();
    }
       return RedirectToAction("Index");
}
catch
{
    return View(model);
}
6
Desmond

Exclude 属性を試してください。
私はそれを使ったことがないことを認めます。

[Exclude]
public Entity Name {get; set;}
2
gdoron