2017-06-07 4 views
0

AutoMapperとEFCoreには非常に新しいので、ここで噛み砕くことができるかもしれないが、私はそれをやっていると思ったが、失敗する可能性があるそれは誰かが正しい方向に私を指すことができるかもしれない場合。AutoMapperとEFCoreを使用してTrackingChangesを実行中にDTOをマッピングする

AutoMapperを使用してエンティティをDTOに変換していますが、これは問題ありません。

私はDTOをエンティティに変換し、EntityFrameworkにすべての変更(プロパティが更新され、リストオブジェクトから削除された子オブジェクトなど)を追跡したいのですが、これは可能ですか?

私はシンプルなPUTメソッドを持っているのであれば、私はこのような何かをしたい、とあなたの変更セットが同じままようにするには、アダプタクラスを作成することができ、残り

public async Task<IActionResult> PutAsync([FromBody] MyDTO model) 
{ 
    // GET OBJECT FROM DATABASE HERE 
    var dbValue = _repos.GetMyObjectUsingId(999); 

    // apply updates 
    _mapper.Map<MyDTO, MyObject>(dbValue, model); 

} 

答えて

0

からautomapperソートを聞かせ: あなたはインターフェイス

からDTOの継承を使用すると、DTOを持っていると言うことがあります:

public interface IFooDTO 
{ 
    int Id { get; set;} 
    string Name { get; set;} 
} 

public class FooDTO : IFooDTO 
{ 
    public int Id { get; set;} 
    public string Name { get; set; } 
} 

は、次に、あなたのエンティティを持っている

public class FooEntity 
{ 
    public int Id; 
    public string name; 
} 

は、そのようにfooというインターフェースを継承しているようなあなたのアダプタを作成:

public class FooAdapter : IFooDTO 
{ 
    FooEntity entity; 
    FooAdapter(FooEntity entity) 
    { 
     this.entity = entity; 
    } 

    public int Id 
    { 
     get {return this.entity.Id;} 
     set {/*Do nothing set by EF*/} 
    } 

    public string Name 
    { 
     get {return this.entity.Name;} 
     set {this.entity.Name = value; } 
    } 

    public void Apply(FooDTO foo) 
    { 
     //I don't remember if this is the correct order but you get the gyst 
     this._mapper.Map<IFooDTO, IFooDTO>(this, foo); 
    } 
} 

次に、あなただけのマッパーでDTOあなたにあなたのIdtoからマップする必要があります。

使用法:

public ActionResult PutFoo(int id, FooDTO foo) 
{ 
    var entity = context.Foos.FirstOrDefault(x => x.Id == id); 
    var adapter = new FooAdapter(entity); 
    adapter.Apply(foo); 
    //Entity has been updated and has original changes 
} 

EDIT

子供は細かい作業だけ同じアダプタパターンを使用し、このためのセッターは多くのコードですが、エンティティの同期

public BarDTO childBar 
{ 
    get { return new BarAdapter(this.entity.Bar).ToDTO(); } 
    set { new BarAdapter(this.entity.Bar).Apply(value) } 
} 

public static void Sync<TEntity, TEntityKey, TDTO>(this ICollection<TEntity> entityCollection, ICollection<TDTO> dtoCollection, 
    Func<TEntity> entityConstructor, Action<TDTO, TEntity> copyAction, 
    Action<TEntity> onDeleteAction, 
    Func<TEntity, TEntityKey> entityKeySelector, 
    Func<TDTO, TEntityKey> dtoKeySelector) 
    where TEntity : class 
    where TEntityKey : struct 
{ 
    dtoCollection = dtoCollection ?? new TDTO[] { }; 
    except = except ?? new TEntityKey[] { }; 

    var dtoIds = dtoCollection.Select(dto => dtoKeySelector(dto)).ToHashSet(); 
    foreach (var entity in entityCollection.Where(x => false == dtoIds.Contains(entityKeySelector(x))).ToArray()) 
    { 
     onDeleteAction(entity); 
     entityCollection.Remove(entity); 
    } 

    var entityCollectionMap = entityCollection.ToDictionary(x => entityKeySelector(x)); 

    foreach (var dtoItem in dtoCollection) 
    { 
     TEntity entity = null; 
     if (dtoKeySelector(dtoItem).HasValue) 
     { 
      entity = entityCollectionMap.ContainsKey(dtoKeySelector(dtoItem)) ? entityCollectionMap[dtoKeySelector(dtoItem)] : default(TEntity); 

     } 

     if (null == entity) 
     { 
      entity = entityConstructor(); 
      entityCollection.Add(entity); 
     } 
     copyAction(dtoItem, entity); 
    } 
} 
+0

これは非常に興味深い...ありがとうございます。また、オブジェクト内の子オブジェクトとリストに対してこの作業を行うことはできますか? automapperを実行し、DTOにない(IDと一致していない)リストから項目を削除しますか? – Gillardo

+0

@ user2736022この回答は役に立ちそうです、私は子オブジェクトの答えを更新しました。うまくいけば、これはあなたのオリジナル投稿を満足させます。あなたは上記のことを行うためにグローバル同期メソッドを使用することができます。ユニオンとICollectionを更新するだけで、多くの余分なコードがわかります。遅れている場合は、別のアップデートに入れます –

+0

getterは簡単です{return this.entity.Bars.Select(b =>新しいBarAdapter(b).ToDTO())。ToList(); } ' –

関連する問題