2012-03-15 6 views
4

AutoMapperを使用して2つの複雑なオブジェクトインスタンスをマージする方法を理解しようとしています。AutoMapper:あるインスタンスから別のインスタンスへのコレクション内のアイテムの値の結合

public class Parent 
{ 
    public List<Child> Children { get; set; } 
} 

public class Child 
{ 
    public string A { get; set; } 
    public string B { get; set; } 
    public string C { get; set; } 
} 

私はParentの2件のインスタンスがあります:

var parentOne = new Parent() 
{ 
    Children = new List<Child>() { new Child() { A = "A", B = "B", C = "C" } } 
}; 

var parentTwo = new Parent() 
{ 
    Children = new List<Child>() { new Child() { C = "Updated value" } } 
}; 

を私はせずに、parentOneからparentTwoに値をマージできるようにしたい親オブジェクトは、子オブジェクトのコレクションであるという性質を持っていますCの値をparentTwoに上書きします。次のように私が作成したマップは、次のとおりです。

Mapper.CreateMap<Parent, Parent>() 
    .ForMember(parent => parent.Children, opt => opt.UseDestinationValue()); 

Mapper.CreateMap<Child, Child>() 
    .ForMember(child => child.C, opt => opt.Ignore()); 

Mapper.Map(parentOne, parentTwo); 

私はそれを理解として、あなたはUseDestinationValue()オプションを使用しない限り、AutoMapperは複雑なプロパティの新しいインスタンスを作成します。ただし、上記のコードを実行した後、parentTwo.C"Updated value"の代わりに"C"になります。

それはList<Child>のインスタンスを保持しているようそれは私には見えますが、それは以内リストをChildの新しいインスタンスを作成しています。残念ながら、私はChildの各インスタンスも保持するマップを考え出すのに苦労しています。

ご協力いただければ幸いです。

答えて

6

私の知る限りでは、AutoMapperはこれをサポートしていないと私はそれがために支援の複雑さだと信じていなシナリオ。

UseDestinationValueは、あなたが推測したコレクションインスタンスでのみ動作します。コレクション要素ではありません。あなたのシナリオでは、各リストには1つのアイテムしかありませんが、子リストオブジェクトを「同期」(最初の要素が最初の要素を更新し、2番目の更新が2番目...など)に更新されるようにします。しかし、3つのリストと5つのリストがあればどうでしょうか?目的地の値がない場合、 "UseDestinationValue"はどういう意味ですか?そして、2つの子リストの中でどのDesintationオブジェクトをマップするかを選ぶにはどうすればよいですか?データベースのシナリオ(それは質問の根本的だったと聞こえます)では、ユニークなIDまたはある種の外部キーがあります。これにより、どのオブジェクトをマップするかを知るために、子オブジェクトを突き合わせることができます。この場合、コレクションの個々の要素に対してUseDestinationValueをサポートする汎用マッピングを記述するのは難しい(IMO)。

+0

ありがとうパトリック - あなたは当然です。私がやっていることは、それぞれのリストに同じ要素があることを前提としています。それが起こっているので、これは私が取り組んでいるものの場合ですが、大部分の状況には実際には当てはまりません。私はおそらく、コレクションを適切に同期させ、AutoMapperに一致する要素のプロパティをマージさせるためにコードを完成させるでしょう。 –

+0

ありがとうございますパトリック:私は同様の質問[ここ](http://stackoverflow.com/questions/14229798/)、あなたのコメントは "しかし、1つのリストが3つと他のリストに5がある場合は?おそらく私がやろうとしていたことは意味をなさないことが示されています。 – Merenzo

4

このシナリオを処理するためのマッピングを思い付くことができなくなる可能性が増しています。 AutoMapperはこのような方法で値をマージするために使用されることは決してなかった。

私はループ内でコレクションを手動で処理することに頼ってきました。この回答の目的のために、私はParent.Aはプロパティを一意に識別していると仮定しています:

Mapper.CreateMap<Parent, Parent>() 
    .ForMember(parent => parent.Children, opt => opt.Ignore()); 

Mapper.CreateMap<Child, Child>() 
    .ForMember(child => child.C, opt => opt.Ignore()); 

Mapper.Map(parentOne, parentTwo); 

foreach (var childTwo in parentTwo.Children) 
{ 
    var childOne = parentOne.Children.Where(child => child.A == childTwo.A).Single(); 
    Mapper.Map(childOne, childTwo); 
} 
+2

こんにちは@Gareth - 私は若干の微調整で、私のアプリであなたのソリューションを実装:親へのマッピング親の後、私は呼ば: '.AfterMap((SRC、DEST)=> {_Garethののforeach loop_}) ; '。これにより、 'Map()'を呼び出すたびに明示的にコーディングするのではなく、マッピング定義でループを維持することができました。 – Merenzo

+0

非常にいいです - 投稿していただきありがとうございます。 –

+0

ガレス - 私の同様の質問[ここ](http://stackoverflow.com/questions/14229798/)にもお答えすることができます。あなたのアプローチはおそらく自分の状況に最適です。 – Merenzo

2

ViewModel(DTO)からEntitySetにマッピングするとき、同じ問題が発生しました。この問題を解決するために書いた方法は次のとおりです。 ViewModelのコレクションをエンティティのコレクションに同期させます。

オートマッパーマッピングでは、コレクションを完全に無視する必要があります。

public void SyncronizeEntitySet<TViewModel, TEntity>(IEnumerable<TViewModel> modelSet, ICollection<TEntity> entitySet, 
     Func<TViewModel, int> sourceKey, Func<TEntity, int> destinationKey, Action<TEntity> setParentKey) 
    where TViewModel : class, new() 
    where TEntity : class, new() 
{ 
    var toDelete = new List<TEntity>(); 
    foreach (var entityItem in entitySet) 
    { 
     var modelItem = modelSet.FirstOrDefault(i => sourceKey(i) == destinationKey(entityItem)); 
     if (modelItem == null) 
     { 
      toDelete.Add(entityItem); 
     } 
     else 
     { 
      Mapper.Map(modelItem, entityItem); 
     } 
    } 

    toDelete.ForEach(i => Delete(i)); 

    foreach (var modelItem in modelSet) 
    { 
     if (sourceKey(modelItem) == 0) 
     { 
      var entityItem = Mapper.Map<TEntity>(modelItem); 
      setParentKey(entityItem); 
      Add(entityItem); 
     } 
    } 
} 
関連する問題