2

リポジトリ パターンと単体テストで MVC 4 を使用しています。シンプルな CRUD 機能を持つ典型的なコントローラーがあります。ビュー モデルを DTO から分離しました。この 2 つを変換する最良の方法を知りたいです。

モデル:

Admin.Models.ProductビューモデルとAdminAssembly.Models.ProductDTOがあります。

コントローラ:

    //repo that handles product operations
    AdminAssembly.Interfaces.IEntityRepository<AdminAssembly.Models.Product> db;
    //default constructor
    public ProductController() { db = new AdminAssembly.Repositories.EntityRepo<AdminAssembly.Models.Product>(new AdminAssembly.Models.EntitiesContext()); }
    //unit testing constructor
    public ProductController(AdminAssembly.Interfaces.IEntityRepository<AdminAssembly.Models.Product> context) { db = context; }

    //
    // POST: /Product/Create

    [HttpPost]
    public ActionResult Create(Admin.Models.Product product) {

        if (ModelState.IsValid) {
            //COMPILE-ERROR: how to convert to DTO?
            db.Add(product);
        }
        return View();

    }

    //
    // GET: /Product/Edit/5

    public ActionResult Edit(int id) {
        //COMPILE-ERROR: how to convert to view model?
        Admin.Models.Product product = db.GetAll().Where(p => p.ID == id);

        return View(product);
    }

2つの間で変換するにはどうすればよいですか?

ビュー モデルで DTO アセンブリを参照し、次のようなことを行いますか? (これで単体テストが中断されませんか?)

//convert to AdminAssembly.Models.Product
db.Add(product.ToDTO());

//convert back to Admin.Models.Product via constructor
Admin.Models.Product product = Admin.Models.new Product(db.GetAll().Where(p => p.ID == id));

ある種のオブジェクト変換ブラック ボックスが必要ですか?

Converter.ToViewProduct(product);

ある種のインターフェース?

または、他の何か?

更新 1:

    public static class Product {
        public static Admin.Models.Product ToView(AdminAssembly.Models.Product dto) {
            Admin.Models.Product viewProduct = new Admin.Models.Product();
            //straight copy
            viewProduct.Property1 = dto.Property1;
            viewProduct.Property2 = dto.Property2;

            return viewProduct;
        }
        public static AdminAssembly.Models.Product ToDTO(Admin.Models.Product viewModel) {
            AdminAssembly.Models.Product dtoProduct = new AdminAssembly.Models.Product();
            //straight copy
            dtoProduct.Property1 = viewModel.Property1;
            dtoProduct.Property2 = viewModel.Property2;

            //perhaps a bit of wizza-majig
            dtoProduct.Property1 = viewModel.Property1 + viewModel.Property2;

            return dtoProduct;
        }
    }
4

3 に答える 3

3

ロングハンド応答

[HttpPost]
public ActionResult Create(Admin.Models.Product product) 
{
  if (ModelState.IsValid)
  {
    //COMPILE-ERROR: how to convert to DTO?
    var dtoProduct = new AdminAssembly.Models.Product();
    dtoProduct.Property1 = product.Property1;
    dtoProduct.Property2 = product.Property2;
    //...and so on
    db.Add(dtoProduct);
  }
  return View();
}

これは冗長で退屈に見えますが (実際にそうです)、最終的にはどこかで実行する必要があります。

Charlino が指摘しているように、このマッピングを別のクラスまたは拡張メソッドで非表示にするか、AutoMapper などのサード パーティを使用することができます。

余談ですが、2 つの異なる名前空間に同じ名前の 2 つのクラスがあると、最終的に混乱を招くことになります (あなたがそうでなくても、次の人があなたのコードを保守する必要があります)。たとえば、すべてのビュー モデルを、Models ではなく ViewModels というフォルダーに配置します。そして、ViewModel または VM を使用してすべてのビュー モデルを追加します。また、すべてのビュー モデルがドメイン モデルに直接マップされるわけではないため、マップ先のドメイン モデルではなく、対象のビューに基づいてビュー モデルに名前を付けるのも良い慣例です。1 つのビューに対して複数のドメイン モデルの一部が必要な場合があり、それによって命名規則が破綻します。

したがって、この特定のケースでは、ビュー モデル バージョンを CreateViewModelに変更Admin.Modelsして名前を変更することをお勧めします。コードははるかに読みやすくなり、メソッド全体で名前空間が散らばることはありません。 Admin.ViewModelsProduct

そのすべてが、次のようなメソッドになります。

[HttpPost]
public ActionResult Create(CreateViewModel viewModel) 
{
  if (ModelState.IsValid)
  {
    var product = new Product();
    product.Property1 = viewModel.Property1;
    product.Property2 = viewModel.Property2;
    //...and so on
    db.Add(product);
  }
  return View();
}
于 2013-03-08T18:04:11.703 に答える
2

AutoMapperというライブラリをチェックしてください。

彼らのウィキから:

オートマッパーとは?
AutoMapper は、一見複雑な問題を解決するために構築された単純な小さなライブラリです。つまり、あるオブジェクトを別のオブジェクトにマップするコードを削除します。このタイプのコードは、書くのがかなり単調で退屈なので、それを行うためのツールを発明してみませんか?

于 2013-03-08T17:29:14.887 に答える
0

AutoMapper を使用したくない場合は、@ Forty-Two で提案されているように、拡張機能を使用できます。マッピングするものの数がそれほど多くない場合は、AutoMapper == YAGNI という理由だけで、このアプローチを使用します。

public static class Extensions
{
    public static ViewModel ToViewModel(this Model )
    {
        var vm = new ViewModel()
        {
            //map
        };
        return vm;
    }
    public static Model ToModel(this ViewModel viewModel)
    {
        var model = new Model()
        {
            //map
        };
        return model;
    }
}

UPDATE のコードに似ていますが、代わりに拡張機能を使用しています。

于 2014-08-20T23:30:15.170 に答える