C# 使用Automapper将DTO映射到实体

C# 使用Automapper将DTO映射到实体,c#,entity-framework,automapper,C#,Entity Framework,Automapper,我有一个实体框架POCO,其结构如下 public class Entity { public virtual int Id { get; set; } public virtual string Name { get; set; } } 我已经为视图使用的该实体创建了一个数据传输对象 public class EntityDto { public int Id { get; set; } public string Name { get; set; } }

我有一个实体框架POCO,其结构如下

public class Entity
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}
我已经为视图使用的该实体创建了一个数据传输对象

public class EntityDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}
现在,我的Global.asax文件中有以下映射代码

Mapper.CreateMap<Entity, EntityDto>();
Mapper.CreateMap<EntityDto, Entity>(); // not sure whether I need this as well?
现在,我该怎么解决这个问题呢?我可以:

  • 以某种方式告诉AutoMapper将实体键属性设置为
    .Ignore()
  • 是否让AutoMapper复制实体键属性
  • .Attach()
    my mapped
    Entity
    并将状态设置为modified

  • 感谢您的帮助。

    尝试将实体作为第二个参数传递给映射

    entity = Mapper.Map<EntityDto, Entity>(model, entity);
    
    entity=Mapper.Map(模型,实体);
    
    否则,您的实体实例将被新实例覆盖,并且您将丢失在第一行中创建的实体

    .Attach()我的映射实体并将状态设置为修改

    public ActionResult编辑实体(实体到模型)
    {
    var entity=Mapper.Map(模型);
    context.Set().Attach(实体);/(或context.entity.Attach(实体);)
    context.Entry(entity).State=System.Data.EntityState.Modified;
    SaveChanges();
    返回视图(模型);
    }
    
    您的上下文在哪里实例化?您应该在EditEntity操作中这样做

    public ActionResult EditEntity(EntityDto model)
    {
        using(var context = new MyContext())
        {
            var entity = Mapper.Map<Entity>(model);
            context.Set<Entity>().Attach(entity); // (or context.Entity.Attach(entity);)
            context.Entry<Entity>(entity).State = System.Data.EntityState.Modified;
            context.SaveChanges();
            return View(model);
        }
    }
    
    public ActionResult编辑实体(实体到模型)
    {
    使用(var context=new MyContext())
    {
    var entity=Mapper.Map(模型);
    context.Set().Attach(实体);/(或context.entity.Attach(实体);)
    context.Entry(entity).State=System.Data.EntityState.Modified;
    SaveChanges();
    返回视图(模型);
    }
    }
    
    DTO到实体转换不需要Automapper的另一个答案是使用DbEntry:

            var oldEntity = DbSet.FirstOrDefault(x => x.Id == updatedEntity.Id);
            var oldEntry = Context.Entry(oldEntity);
    
            oldEntry.CurrentValues.SetValues(updatedEntity);
    
    您不需要任何附加/状态检查,因为您首先获取旧实体,因此它附加了更改跟踪。此外,CurrentValues.SetValues可以接受不同的类型,在本例中,updateEndity是DTO。设定值文档解释如下:

    通过读取给定对象的值来设置此字典的值。给定对象可以是任何类型。将读取对象上的任何属性,其名称与字典中的属性名称匹配并且可以读取。其他属性将被忽略。例如,这允许从简单数据传输对象(DTO)复制属性


    看来它已经可以像automapper那样执行了。

    不幸的是,我已经尝试过了,导致了相同的问题-基本上automapper说它找不到映射配置,就像我从上下文中检索我的
    实体时一样,这不再只是您的平均POCO,因此AutoMapper不知道该做什么。如果实体上有其他属性您还没有列出,您最好告诉AutoMapper忽略它们:。FormMember(dest=>dest.PropertyToIgnore,opt=>opt.UseDestinationValue)这就是问题所在,在我创建AutoMapper映射时,实体只是一个POCO,因此不包含EF在检索时创建的任何额外实体内容,所以我不能告诉AutoMapper忽略它们。天哪,我不知道你可以用Map做这件事。太棒了。@dark_ruby非常感谢你,它解决了我的问题。太棒了,这刚刚奏效。给我一些时间来尝试我的实际项目。很高兴我可以alt tab并复制粘贴。。我的意思是帮助你这对我完全有效。Mapper.Map(model,entity)解决方案对我不起作用,因为当你有一个嵌套的实体时,你会更新它(因此你的属性现在引用一个不同的(已经被跟踪的)实体),automapper解决方案会“覆盖”以前引用的实体,changetracker会抱怨它已经在跟踪一个具有该标识符的实体。
    
    public ActionResult EditEntity(EntityDto model)
    {
        using(var context = new MyContext())
        {
            var entity = Mapper.Map<Entity>(model);
            context.Set<Entity>().Attach(entity); // (or context.Entity.Attach(entity);)
            context.Entry<Entity>(entity).State = System.Data.EntityState.Modified;
            context.SaveChanges();
            return View(model);
        }
    }
    
            var oldEntity = DbSet.FirstOrDefault(x => x.Id == updatedEntity.Id);
            var oldEntry = Context.Entry(oldEntity);
    
            oldEntry.CurrentValues.SetValues(updatedEntity);