Сопоставление DTO с сущностью с помощью Automapper

у меня есть Entity Framework 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; }
}

теперь у меня есть следующий код отображения в моем глобальном.файл 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 и установлено состояние modified?

любая помощь всегда приветствуется.

3 ответов


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

попробуйте передать entity в качестве второго параметра в ваше сопоставление.

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

в противном случае ваш экземпляр сущности перезаписывается новым экземпляром, и вы теряете сущность, созданную в первой строке.


альтернативный ответ, который не требует Automapper для преобразования 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 объясняется следующим образом:

устанавливает значения этого словаря путем чтения значения данного объекта. Данный объект может быть любого типа. Любое свойство объекта с именем, которое соответствует имени свойства в словаре, и можно будет читать. Другие свойства будут проигнорированы. Это позволяет, например, копировать свойства из простых объектов передачи данных (DTOs).

похоже, что он уже может работать в режиме automapper-esque.