2011-07-01 17 views
3

私のプロジェクトでは、拡張メソッド.ToViewModel()を実装することで、AutoMapperの使用を簡単にしようとしています。基本的には標準的な呼び出しを包むラッパーになりますが、何かをマッピングするたびにどれくらい入力しなければならないか迷ってしまうことがよくあります。 2の比較:AutoMapperを使用した.ToViewModel()の実装

var viewModel = Mapper.Map<DomainEntityType, ViewModelType>(entity); 
// or... 
var viewModel = entity.ToViewModel(); 

私はすべての私のエンティティがIEntityを拡張させてきた、とエンティティに対応するすべてのviewmodelsは()IViewModel<IEntity>を拡張し、次の拡張メソッドを書かれた)=数2は甘いだろうと感じ

public static IViewModel<TEntity> ToViewModel<TEntity>(this TEntity entity) 
    where TEntity : IEntity 
{ 
    return Mapper.Map<TEntity, IViewModel<TEntity>>(entity); 
} 

しかし、私はこの飛行をすることができません。

次のNUnitテストでは、これをテストしようとしています(Assert.AreEqualが実際にテストしているかどうかはわかりませんが、参照平等が必要なのでしょうか?テストはメッセージ私のテストは間違ったことをテストされるかもしれないという事実を除いて

Expected: &ltCastle.Proxies.IViewModel`1Proxy> 
But was: <Castle.Proxies.IViewModel`1Proxy>
[Test] 
public void DomainEntityTypeMapsViewModelType() 
{ 
    var entity = new DomainEntityType(); 
    var oldskool = Mapper.Map<DomainEntityType, IViewModel<Entity>>(entity); 
    var extension = inspectionObject.ToViewModel(); 

    Assert.AreEqual(oldskool, extension); 
} 

で失敗し、私はAutoMapperがどのように機能するかについての基本的な何かが足りないのですか? AutoMapperはこれまでに何かをインターフェイスに正しくマッピングできますか? (私はクラスEntityViewModelを持っていますが、それはViewModel<Entity>を実装していますが、私はAutoMapperに特に言及していません...)

+0

ジェネリック型パラメータの制約を_TEntity:Entity_のどこに変更してみてください。 Btw、デバッガで2つのオブジェクトが同じで、期待通りに見えるようにしようとしていますか?また、Assert.AreEqualをAssert.AreSameに変更しようとすると、2つのオブジェクトが同じオブジェクトインスタンスを参照しているかどうかを確認します – sll

+0

これを達成する方法を知りたいと思います... – Baldy

+0

@Baldy:私はこれを解決しました - 私の答えを見てくださいこの質問に。 –

答えて

2

私は最終的にこれを一般的な方法で行いました。私のオブジェクトの調整が必要でしたが、ここで私は何をしましたか:

これまでのところ、ほとんどのエンティティはEntity<TId>(通常Entity<int>ですが、IDはGUIDなどの別のデータ型になる可能性があります)を継承しています。 turnはインターフェイスIEntity<TId>(単一のプロパティpublic TId ID {get;})を実装します。 Entity<TId>を継承しない少数のエンティティは、少なくともIEntity<TId>を実装します。

私はEqualsGetHashcodeをオーバーライドする新しいクラス、作成:このクラスから継承し

public class ViewModel<TEntity, TId> : IEntity<TId> 
    where TEntity : IEntity<TId> 
{ 
    public TId ID { get; set; } 

    public override bool Equals(object obj) 
    { 
     var viewModel = obj as ViewModel<TEntity, TId>; 
     return viewModel != null && Equals(viewModel); 
    } 

    public bool Equals(ViewModel<TEntity, TId> other) 
    { 
     return ID.Equals(other.ID); 
    } 

    public override int GetHashCode() 
    { 
     // Not only returning ID.GetHashCode() in case I want to add more 
     // properties later... 
     var hash = 7; 
     hash = (hash * 17) + ID.GetHashCode(); 

     return hash; 
    } 
} 

、すべての私のviewmodels(およびeditmodelsを):

public class EntityViewModel : ViewModel<EntityType, int> 
{ 
    // data properties 
} 

私はその後、私のエンティティを拡張することができ次の拡張方法を使用したビューモデル:

public static TViewModel To<TViewModel>(this IEntity entity) where TViewModel : class 
{ 
    return Mapper.Map(entity, entity.GetType(), typeof(TViewModel)) as TViewModel; 
} 

public static TEntity ToEntity<TEntity, TId>(this ViewModel<TEntity, TId> viewmodel) where TEntity : class, IEntity<TId> 
{ 
    return Mapper.Map(viewmodel, viewmodel.GetType(), typeof(TEntity)) as TEntity; 
} 

この作業を行うための重要な概念は、.Mapという一般的なオーバーロードを放棄することでした。なぜなら、コンパイル時にマップしたいと思う正確な型がわからなかったからです。

私は今、次の構文を使用して、タイプ間で前後に移動することができます。

コントローラでの実装からAutoMapperを抽象化の私の当初の目標がよくなっているので、私は、と非常に満足して
var entity = new EntityType(); 
var viewmodel = entity.To<EntityViewModel>(); 

var backagain = viewmodel.ToEntity(); 

達成された。

IEntityの非ジェネリックバージョンもあります。これは空のインターフェイスで、IEntity<T>から継承されています。これは鈍いと見なされるかもしれませんが、汎用バージョンを使用しない単純な理由があります:もしそうした場合、拡張メソッドの型引数として指定する必要があります。推論型引数はすべてかどうかの関係ではないので、上記の構文の代わりにentity.To<EntityViewModel,int>()になります。

関連する問題