使用Automapper将DTO映射到实体

时间:2012-10-31 11:04:36

标签: 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; }
}

现在,我在Global.asax文件中有以下映射代码。

Mapper.CreateMap<Entity, EntityDto>();
Mapper.CreateMap<EntityDto, Entity>(); // not sure whether I need this as well?

一切正常,我将DTO传递给我的观点确定,我可以从我的Entity模型中创建EntityDto的新实例。当我尝试编辑Entity时出现问题;我知道这是由于AutoMapper失去了EF为跟踪对象更改而创建的实体密钥,但是通过一些来源读取似乎并不是一个明确的解决方案。这是我用来编辑我的实体的动作。

public ActionResult EditEntity(EntityDto model)
{
    var entity = context.Entities.Single(e => e.Id == model.Id);
    entity = Mapper.Map<EntityDto, Entity>(model); // this loses the Entity Key stuff
    context.SaveChanges();

    return View(model);
}

现在,我该怎么做才能解决这个问题?我可以:

  1. 以某种方式告诉AutoMapper .Ignore()实体密钥属性?
  2. 获取AutoMapper以复制实体密钥属性?
  3. .Attach()我映射的Entity并将状态设置为已修改?
  4. 任何帮助总是受到赞赏。

3 个答案:

答案 0 :(得分:14)

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

entity = Mapper.Map<EntityDto, Entity>(model, entity);

否则,您的实体实例将被新实例覆盖,并且您将丢失在第一行中创建的实体。

答案 1 :(得分:8)

  

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

public ActionResult EditEntity(EntityDto model)
{
    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);
}

您的上下文在哪里实例化?你应该在你的EditEntity动作imo。

中做到这一点
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);
    }
}

答案 2 :(得分:2)

不需要Automaper进行DTO到实体转换的替代答案是使用DbEntry:

        var oldEntity = DbSet.FirstOrDefault(x => x.Id == updatedEntity.Id);
        var oldEntry = Context.Entry(oldEntity);

        oldEntry.CurrentValues.SetValues(updatedEntity);

您不需要任何附加/状态检查,因为您首先获取旧实体,因此它附加了更改跟踪。此外,CurrentValues.SetValues可以接受不同的类型,在本例中,updatedEntity是DTO。 Set Values文档解释如下:

  

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

所以看起来它已经可以以自动化程序的方式执行。