9

ASP.NET MVC プロジェクトでは、AutoMapper を使用してドメイン モデルからビューモデルにマップし、その際に階層をフラット化することもあります。これは魔法のように機能し、ビューのレンダリング ロジックを非常に無駄のないシンプルなものにします。

特にオブジェクトを更新するときに、ビューモデル(またはポストモデルまたは編集モデル)からドメインモデルに逆に行きたいときに混乱が始まります。次の理由により、自動/双方向マッピングを使用できません。

  1. フラット化された階層をアンフラット化する必要があります
  2. ドメイン モデルのすべてのプロパティは変更可能である必要があり、パブリック セッターが必要です。
  3. ビューからの変更は、常にフラットなプロパティがドメインにマップされるだけではなく、" ChangeManagerForEmployee()" などのメソッドを呼び出す必要がある場合もあります。

これは、Jimmy Bogards の記事: The case for two-way mapping in AutoMapper でも説明されていますが、これに対する解決策については詳しく説明されていません。

EditModel から CommandMessages へ - 緩く型付けされた EditModel から厳密に型付けされた分割されたメッセージへ。1 つの EditModel で半ダースのメッセージが生成される場合があります。

同様のSO の質問には、Mark Seemanによる回答があります。

抽象マッパーとサービスを使用して、PostModel をドメイン オブジェクトにマップします

ただし、詳細 (概念的および技術的な実装) は省略されています。

現在の私たちの考えは次のとおりです。

  1. コントローラーのアクション メソッドで FormCollection を受け取る
  2. 元のドメイン モデルを取得し、viewModelOriginal と viewModelUpdated にフラット化します
  3. を使用して FormCollection を viewModelUpdated にマージするUpdateModel()
  4. 一般的なヘルパー メソッドを使用して、viewModelOriginal と viewModelUpdated を比較します。
  5. A) Jimmy Bogard 風に CommandMessages を生成するか、B) プロパティとメソッドを介して違いをドメイン モデルに直接変更します (おそらく AutoMapper を介して 1-1 プロパティを直接マッピングします)。

FormCollection から editmodel/postmodel を介してドメイン モデルに至るまでの例を誰かが提供できますか? 「CommandMessages」または「抽象マッパーとサービス」?

4

4 に答える 4

2

私は次のパターンを使用します。

[HttpPost]
public ActionResult Update(UpdateProductViewModel viewModel)
{
    // fetch the domain model that we want to update
    Product product = repository.Get(viewModel.Id);

    // Use AutoMapper to update only the properties of this domain model
    // that are also part of the view model and leave the other properties unchanged
    AutoMapper.Map<UpdateProductViewModel, Product>(viewModel, product);

    // Pass the domain model with updated properties to the DAL
    repository.Update(product);

    return RedirectToAction("Success");
}
于 2012-07-03T15:23:50.533 に答える
1

CQRS(Command Query Responsibility Segregation - これはあなたが見逃していた概念かもしれないと思います) を検討することをお勧めします。

これは基本的に、データ ソースからの読み取りとデータ ソースへの書き込みのロジックを分離する方法であり、読み取りと書き込みに異なるデータ モデルを使用することを意味することさえあります。

これは始めるのに良い場所かもしれません: http://abdullin.com/cqrs/

于 2012-07-03T23:28:48.053 に答える
0

ここには、私がやってきたことといくつかの類似点があります。私のビュー モデルの階層は、ドメイン オブジェクトの同等物からいくらか平坦化されているだけですが、単に逆マッピングするのではなく、保存時に明示的なサービス メソッドを呼び出して、子コレクションへの追加、重要な値の変更などを行う必要があります。また、スナップショットの前後を比較する必要があります。

私の保存は、JSON として MVC アクションに投稿された Ajax であり、MVC によって魔法のようにビュー モデル構造にバインドされたアクションに入ります。次に、AutoMapper を使用して、最上位のビュー モデルとその子孫を同等のドメイン構造に変換します。新しい子項目がクライアントに追加された場合 (私は Knockout.js を使用しています)、明示的なサービス メソッドを呼び出す必要がある場合に備えて、多数のカスタム AutoMapper ITypeConverters を定義しました。何かのようなもの:

            foreach (ChildViewModel childVM in viewModel.Children)
        {
            ChildDomainObject childDO = domainObject.Children.Where(cdo => cdo.ID.Equals(childVM.ID))).SingleOrDefault();
            if (childDO != null)
            {
                Mapper.Map<ChildViewModel, ChildDomainObject>(childVM, childDO);
            }
            else
            {
                MyService.CreateChildDO(someData, domainObject); // Supplying parent
            }
        }

削除についても同様のことを行いますが、このプロセスは構造全体に非常にうまくカスケードします。フラット化された構造は、操作が簡単か難しいかのどちらかだと思います-上記のマッチングを行うIDを持つAbstractDomainViewModelがあり、これが役立ちます。

サービス層がオブジェクト グラフの他の部分に影響を与える可能性があるトリガー検証を呼び出すため、更新の前後に比較を行う必要があります。これにより、Ajax 応答として返す必要がある JSON が決まります。私は UI に関連する変更のみに関心があるため、保存されたドメイン オブジェクトを新しいビュー モデルに変換し、2 つのビュー モデルを比較するためのヘルパー メソッドを用意します。

于 2012-07-06T05:51:32.213 に答える
0

オプション C: すべてをコントローラー アクションに入れます。次に、それが難しい場合は、サービス (抽象マッパー) またはメッセージとしてのメソッド (コマンド メッセージの方法) に分解します。

コマンド メッセージの方法:

public ActionResult Save(FooSaveModel model) {
    MessageBroker.Process(model);

    return RedirectToAction("List");
}

そしてプロセッサ:

public class FooSaveModelProcessor : IMessageHandler<FooSaveModel> {

    public void Process(FooSaveModel message) {
        // Message handling logic here
    }

}

これは、フォームの「処理」をコントローラ アクションから個別の特殊なハンドラに移すだけです。

しかし、コントローラーのアクションが複雑になる場合にのみ、私は本当にこのルートに行きます。それ以外の場合は、フォームを取得して、必要に応じてドメイン モデルに対して適切な更新を行ってください。

于 2012-07-04T04:01:40.587 に答える