简体   繁体   English

使用AutoMapper和EFCore跟踪更改时将DTO映射到实体

[英]Mapping DTO to Entity while TrackingChanges with AutoMapper and EFCore

Very new to AutoMapper and EFCore, so maybe biting off more than i can chew here, but thought i would give it a go, but failing, and maybe it aint possible, but if it is maybe someone can point me in the right direction. 对AutoMapper和EFCore来说是非常新的东西,所以也许比我在这里所能做的要多得多,但我想我可以尝试一下,但是失败了,也许没有可能,但是如果有人可以指出我正确的方向。

I am using AutoMapper to convert my entities to a DTO, this is fine. 我正在使用AutoMapper将我的实体转换为DTO,这很好。

Now i would like to convert my DTO to an entity and have EntityFramework track all the changes (property updated, child object removed from list etc), but is this possible? 现在我想将我的DTO转换为一个实体,并让EntityFramework跟踪所有更改(属性更新,从列表中删除子对象等),但是这可能吗?

So if i have a simple PUT method, i would like to do something like this, and let automapper sort out the rest 因此,如果我有一个简单的PUT方法,我想做这样的事情,然后让automapper整理其余的内容

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);

}

You can create an adapter class so your change set remains the same: Have you DTO's inherit from an interface 您可以创建一个适配器类,以便您的更改集保持不变:您是否从接口继承了DTO?

Say you have a 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; }
}

Then you have your entity 然后你有你的实体

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

Then create your adapter like so which inherits from the foo interface: 然后像这样创建您的适配器,该适配器继承自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);
   }
}

Then you just need to Map from your Idto to you dto in the mapper. 然后,您只需要在映射器中将您的Idto映射到您的dto。

Usage: 用法:

 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 编辑

Children Work fine just use the same adapter pattern the setter for this is a lot of code but 儿童工作正常,只是使用相同的适配器模式,因此设置程序的设置很多,但是

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

Syncing Entities: 同步实体:

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM