39

現在、ASP.NET MVC プロジェクトに取り組んでいます。

チームの一部の開発者は、自動生成されたデータベース エンティティをビューに直接バインドしたいと考えています。

他の開発者は、オーダーメイドの ViewModel を作成し、それらをビューにバインドしたいと考えています。

客観的に、両方のアプローチの長所と短所は何ですか?

(「データベース エンティティ」とは、LINQ to SQL、Entity Framework、LLBLGen など、ORM フレームワークが生成する自動生成クラスを指しています)。

4

8 に答える 8

50

ビューでビューモデルをAutoMapper使用し、エンティティからビューモデルを簡単に作成するようなものを使用してください。

短所:

  1. 特に、ビュー モデルとエンティティがまったく同じプロパティを持っている場合、コードを複製しているように感じることがあります。

長所:

  1. 多くの場合、オブジェクトをより単純な形式 (フラット化と呼ばれます) で表現する必要がありますが、サーバー側では完全な忠実度が必要です。これにより、ドメイン モデルをプレゼンテーション クラフトで台無しにすることなく、2 つの間を移行できます。
  2. 集約ルートには、多くの場合、特定のビューに関係のない多くの値オブジェクトと追加のエンティティが含まれており、ビュー モデルでそれらを省略すると、操作が簡単になります。
  3. エンティティには、API の観点からは適切な双方向参照が多数ありますが、JSON や XML などのエンティティをシリアル化すると、まったくの地獄になります。ビュー モデルは、これらの循環参照を排除します。
  4. 同じエンティティを使用することがよくありますが、ビューごとに異なる方法で使用できます。1 つのタイプで両方のニーズのバランスを取ろうとすると、大きな混乱が生じる可能性があります。
于 2012-06-07T08:39:53.367 に答える
16

ビューで未加工のデータベース エンティティを使用してはならないというのが正統です。他のルールと同様に、エンティティをよく理解し、その結果を理解している場合は破ることがありますが、特にチームで作業し、将来人々によって維持されるコードを使用する場合は、そのルールを破ってはならない非常に十分な理由があります。あなたほどルールやエンティティを理解していない人もいます。主な理由は次のとおりです。

  1. ORM 遅延読み込み。Customer が遅延ロードされたコレクション Order を持っていると想像してください。Customer を View に渡し、Orders を反復処理します。Orders テーブルで N*1 を選択します。ただし、これは、データベース接続をビューで開いておく必要があることも意味します。ビューがレンダリングされる前に発生する Action_Executed イベントでデータベース コンテキストを破棄する「アクションごとのトランザクション」を使用するパターンがあります。そのため、データベースが破棄された後にデータベースにアクセスしようとしている可能性があります。今それをしていなくても、おしゃれだから将来誰かがそのパターンを実装するかもしれません.

  2. ViewModel の問題は、db モデルとは異なります。たとえば、通常、ViewModel プロパティを検証属性で装飾します。これらは通常、異なるか、データベースではなく UI のみに関係します。データベース エンティティにバインドすると、これらすべての UI の問題が DB エンティティを汚染していることがわかります。

  3. 2 に関連 - ViewModel の要件により、計算されたプロパティまたは派生プロパティが要求される場合があります。たとえば、名と姓から構成される Fullname などです。これらの種類のものは、ViewModel に保持するのが最適です。

  4. データベースから分離して、ViewModel を単体テストできます。ViewModel には、単体テストが必要な非常に多くのロジックが含まれる可能性があります。これは、データベースに関連付けられていない場合 (EF エンティティと同様)、テストが容易です。

一般に、ViewModel の作成と維持は (AutoMapper がなくても) オーバーヘッドではなく、全体的な開発パターンとしてはるかに優れていることがわかります。最も単純なケース (たとえば、静的データのルックアップ リスト) を除いて、すべてに推奨します。

于 2012-06-07T08:51:58.873 に答える
12

ビューモデルを使用することが唯一の方法であると信じているため、ORMエンティティの長所はありません:)ビューモデルはビューにデータを提供するだけでなく、ビューの外観(テンプレートを定義することによって)または検証方法(追加することによって)も定義しますデータ注釈または IDataErrorInfo の実装)。

ビュー モデルの使用:

長所:

  • ビュー モデルには、ビューに必要なプロパティのみが含まれ、他には何も含まれていません。
  • ビュー モデルには、データ注釈または IDataErrorInfo を使用した特定の検証規則が含まれる場合があります。
  • ビュー モデルは、異なるデータベース エンティティの値を組み合わせることができます。
  • ビュー モデルはそれ自体を文書化しており、どのフレームワークにも関連付けられていません。
  • ビュー モデルは、フォームでは提供されていないが、ORM エンティティに含まれていた値を含む、偽造された POST からユーザーを保護します。
  • ビュー モデルの表示テンプレートを簡単に指定し、DisplayForまたはEditorForヘルパーを使用して多くの場所で再利用できます。

ORM エンティティの使用:

短所:

  • ORM エンティティには既にデータ注釈が含まれているため、検証が台無しになる可能性があります。例: ユーザーのパスワード フィールドは としてマークされている場合がありRequiredますが、基本的なユーザー情報のみを変更する場合は必要ありません。
  • ORM エンティティはフレームワーク (エンティティ フレームワーク) に強く結び付けられており、ルールを実装するのは簡単ではない場合があります。
  • ORM エンティティには複数のビューのプロパティを含めることができますが、異なるビューの検証ルールを分離するのは困難です。
  • 遅延読み込みで ORM エンティティを使用すると、ビューがレンダリングされるときに SQL クエリを実行できるようになります。それは起こるべきではありません。
  • ORM エンティティを使用すると、小さな SQL クエリではなく巨大な SQL クエリを使用することになります。名と姓のドロップダウンを表示する場合は、エンティティ全体ではなく、データベースから名と姓のみを取得する必要があります。
于 2012-06-07T09:00:32.153 に答える
8

これまでの回答に感謝します-両方のアプローチの長所/短所を理解するのに大いに役立ちました。他の誰も言及していないことを追加する必要があります。

オーバーポスティング攻撃

DB エンティティに直接バインドする場合の心配な欠点は、「オーバーポスティング攻撃」です。これは、攻撃者が FireBug ほど高度ではないツールを使用して、ユーザーが編集できるようには意図されていないが、DB エンティティに存在するフォーム フィールドを挿入できる場所です。

「プロフィールの編集」ページを考えてみましょう。ビューは次のようになります。

@using(Html.BeginForm() {
  <div>
    @Html.LabelFor(x=> x.FirstName)
    @Html.TextBoxFor(x=> x.FirstName)
  </div>
  <div>
    @Html.LabelFor(x=> x.LastName)
    @Html.TextBoxFor(x=> x.LastName)
  </div>

  <input type="Submit" value="Save" />
}

次の HTML をレンダリングします。

<form action="/profile/edit" method="post">
  <div>
    <label for="FirstName">FirstName</label>
    <input type="text" name="FirstName" value="" />
  </div>
  <div>
    <label for="LastName">LastName</label>
    <input type="text" name="LastName" value="" />
  </div>

  <input type="Submit" value="Save" />
</form>

FireBug を使用すると、攻撃者はフォーム内に HTML のチャンクを挿入するだけで済みます。

  <input type="hidden" name="IsAdmin" value="true" />

...そして突然、ユーザーは非常に予期せぬ有害な方法でデータを変更できるようになります。

さらに恐ろしい非表示のフォーム フィールドを次に示します。

  <input type="hidden" name="ShoppingCart.Items[0].Price" value="0.01" />
  <input type="hidden" name="BankAccount.Balance" value="1000000" />
  <input type="hidden" name="User.Administrator.Password" value="hackedPassword" />

痛い!

情報提供元: http://hendryluk.wordpress.com/tag/asp-net-mvc/

于 2012-06-07T21:59:38.560 に答える
5

ASP.NET ビューで NHibernate エンティティを直接使用するアプリを開発しようとしたことがあります。ビジネスロジックレイヤーやコントローラーではなく、ビューから直接実行される遅延読み込みと遅延 SQL 実行で多くの問題に遭遇しました。ビューモデルに移行してオートマッパーを使用すると、これらの問題がすべて解決され、アプリのテスト、デバッグ、保守が容易になるようです。

また、ビュー モデルは、ページに必要なすべての関連データを保持するのに役立つこともわかりました。これに動的 ViewBag を使用することを好む開発者もいますが、これはテストとデバッグには適していません。

特に、ドロップダウン リストから関連付けられたエンティティを選択する場合は、ビュー モデルを使用すると簡単になりました。

AutoMapper は、このプロジェクトの命の恩人でした。大量のマッピング コードを記述する必要がなくなりました。私がしなければならなかったのは、ビュー モデルを作成し、エンティティからビュー モデルにコントローラーを自動マッピングすることだけでした。

于 2012-06-07T09:41:51.220 に答える
3

バックエンド エンティティをクライアントに公開しないでください。実際のアプリケーションには、CRUD ではなく動作があります。エンティティをビューにデータバインドする場合、クライアント側で動作が必要なときに泥だらけのハックを掘り下げるのは時間の問題です。

于 2012-06-07T11:43:21.223 に答える
2

私は、hackedbychinese とまったく同じ感情を追加しようとしていました。また、ルックアップリストへのfkを使用すると、エンティティモデルがそのテーブル内の単一のIDへのポインターを保持するだけなので、ビューモデルを使用する必要があります。ビューモデルを使用すると、必要な入力済みリストをビューに渡すことができます-ほら。

また、ビューモデルには必要に応じて控えめなロジックを含めることができますが、これはエンティティ モデルには当てはまりません。また、検証はビューの使用によって異なる場合があるため、「ビュー」要件ごとに異なる検証を適用できます。

ViewModel の主な目的は、関心を分離することです。ビューをモデルの実装の詳細から分離します。

于 2012-06-07T08:47:01.433 に答える
0

ビュー、特にフォームで DB エンティティを使用することは、重大なセキュリティ上の問題です。次の POCO オブジェクトを取得します

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
    public bool IsAdmin { get; set; }
}

ここで、ユーザーが電子メールを変更できるビューを表示しているとします。ビュー モデルの代わりに Db エンティティを使用する場合にフォーム結果を処理するための MVC メソッドは次のようになります:

public class HomeController : Controller
{
    [HttpPost]
    public ActionResult ChangeEmail(User user)
    {
        //....
    }
}

Asp.net のモデル バインドは、モデル内のプロパティの名前に一致する GET または POST パラメーターを探すことによって機能します。したがって、ユーザーがしなければならないことはIsAdmin=true、POSt パラメーターと viola に追加することだけです。関数に渡されるモデルにChangeEmailは、IsAdmin プロパティが true に設定されます。これは非常に簡単に誤ってデータベースに追加され、ユーザーはデータを変更するための自由なアクセスが可能になります。彼らは変化にアクセスできませんでした。

これは、ユーザーのアクセス許可、エンティティの所有者の変更 (質問をあなたではなく私に関連付ける)、元の作成日の変更などに適用されます...

于 2012-06-14T03:58:42.223 に答える