Сопоставление 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);
}
теперь, что мне сделать, чтобы решить эту проблему? Могу Ли Я:
- как-то скажите AutoMapper
.Ignore()
свойства ключа сущности? - заставить AutoMapper скопировать свойства ключа сущности?
-
.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.