2011-10-23 6 views
1

同僚、 私たちのプロジェクトでは、AutoMapperを使用してモデルをマップしています。汎用クラスの簡略化は可能ですか?

我々はモデルがあります:私たちは、次のようなものを定義することがビューモデルにモデルをマッピング

public class PersonView 
{ 
    public string Name { get; set; } 
    public string Location { get; set;} 
} 

public class Location 
{ 
    public string Address { get; set; } 
} 

public class Person 
{ 
    public string Name { get; set;} 
    public Collection<Location> Locations { get; set; } 
} 

また、我々はビューモデルを持っている

Mapper.CreateMap<Person, PersonView>(d=>d.Name, opt=>opt.FromMap(s=>s.Name); 
Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.FromMap(s=>s.Locations.First().Address); 

BUT:Locationsに要素が含まれていないか、nullの場合、例外が発生します。

反対側から

、我々は値を取得する関数を定義することができます。これは読みにくい表現

Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.FromMap(s=> 
{ 
    var item = s.Locations.FirstOrDefault(); 
    if(item == null) 
    { 
     return string.Empty; 
    } 

    return item.Address; 
}); 

。そして、マッピングを単純化するためにIValueResolverを作成してみます。

Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.ResolveUsing(
    new CollectionItemResolver<Person, Location, string>(p=>p.Locations, i=>i.Address))); 

は、一般的なリゾルバを簡素化することが可能です:

public class CollectionItemResolver<TSource, TSourceItem, TResult> 
    where TSource : class 
    where TSourceItem : class 
{ 
    private readonly Func<TSource, IEnumerable<TSourceItem>> _sourceSelector; 
    private readonly Func<TSourceItem, TResult> _selector; 
    private readonly TResult _defaultValue; 

    public CollectionItemResolver(Func<TSource, IEnumerable<TSourceItem>> source, Func<TSourceItem, TResult> selector) 
     : this(source, selector, default(TResult)) 
    { 
    } 

    public CollectionItemResolver(Func<TSource, IEnumerable<TSourceItem>> source, Func<TSourceItem, TResult> selector, TResult defaultValue) 
    { 
     _sourceSelector = source; 
     _selector = selector; 
     _defaultValue = defaultValue; 
    } 

    public TResult Resolve(TSource source) 
    { 
     var items = _sourceSelector(source); 

     if (items == null) 
     { 
      return _defaultValue; 
     } 

     var item = items.FirstOrDefault(); 
     if (item == null) 
     { 
      return _defaultValue; 
     } 

     var value = _selector(item); 
     return value; 
    } 
} 

そして、このようなものを使うのか? たとえば、ネストされたアイテムのタイプを定義しないでください。

new CollectionItemResolver<Person, string>(p=>p.Locations, i=>i.Address))); 

おかげで、この程度

+1

'Gents'?あなたの質問を読んでいる女性はどうですか? –

+0

@DarinDimitrov - ストレートな顔でそれを言って+1。 – Steve

+0

私は式に戻ります。それは私のために読むのがずっと簡単でした。 – Enigmativity

答えて

1

方法:

Mapper.CreateMap<Person, PersonView>(d=>d.Address, opt=>opt.FromMap(s=>s.Locations.Select(loc=>loc.Address).FirstOrDefault()); 

購入方法、AutomapperNull PS

string.Emptyに変換する方法を知っている、あなたは常にnullコレクション Locationsがないと思っています。 でもない場合は、その後、私はこの extension使用することをお勧め:

public static IEnumerable<TSource> NullToEmpty<TSource>(
    this IEnumerable<TSource> source) 
{ 
    if (source == null) 
     return Enumerable.Empty<TSource>(); 

    return source; 
} 

を、結果はこのようなものになります。 OPT => opt.FromMap(S => s.Locations.NullToEmpty()=(LOCを選択> loc.Address).FirstOrDefault());

関連する問題