Сопоставление 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; }
}

Теперь у меня есть следующий код сопоставления в моем файле Global.asax.

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

Все работает нормально, я передаю DTO своим представлениям, и я могу создать новый экземплярEntity от моегоEntityDto модель. Проблема возникает, когда я пытаюсь отредактироватьEntity; Я знаю, что это происходит из-за того, что AutoMapper теряет Entity Key, который 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() свойства Entity Key?Получить AutoMapper, чтобы скопировать свойства Entity Key?.Attach() мой картированныйEntity и установить состояние на изменение?

Любая помощь всегда ценится.

Ответы на вопрос(3)

тображения.

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

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

 dark_ruby31 окт. 2012 г., 12:19
если в Entity есть другие свойства, которые вы не перечислили, вы также можете указать AutoMapper игнорировать их: .ForMember (dest => dest.PropertyToIgnore, opt => opt.UseDestinationValue)
 Paul Aldred-Bann31 окт. 2012 г., 12:15
К сожалению, я уже пробовал это, вызывает ту же проблему - в основном AutoMapper говорит, что не может найти конфигурацию сопоставления, как когда я получил свойEntity Исходя из контекста, это больше не просто ваш средний POCO, поэтому AutoMapper не знает, что делать.
 Worthy720 дек. 2016 г., 06:18
Святой КРУД Я не знал, что ты сможешь сделать это с Картой. Удивительно.
 AminM30 окт. 2018 г., 21:31
@ dark_ruby большое спасибо, это решит мою проблему
 Paul Aldred-Bann31 окт. 2012 г., 12:23
Это проблема, в то время как я создаю свои сопоставления AutoMapperEntity это просто POCO, поэтому он не содержит никаких дополнительных сущностей, которые EF создает при извлечении, поэтому я не могу сказать AutoMapper игнорировать их.
Решение Вопроса

.ия?

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);
    }
}
 Pluc31 окт. 2012 г., 12:34
Рад, что я мог alt-tab и скопировать вставить .. Я имею в виду помочь вам. :)
 Paul Aldred-Bann31 окт. 2012 г., 12:32
Это именно то, что я искал, еще раз спасибо!
 Paul Aldred-Bann31 окт. 2012 г., 12:30
Гениально, это только что сработало. Дайте мне несколько минут, чтобы попробовать в моем настоящем проекте.

который не требует Automapper для преобразования DTO в Entity, использует DbEntry:

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

        oldEntry.CurrentValues.SetValues(updatedEntity);

Вам не нужна проверка присоединения / состояния, потому что вы сначала получаете старую сущность, поэтому к ней прикреплено отслеживание изменений. Кроме того, CurrentValues.SetValues может принимать другой тип, в этом примере updatedEntity - это DTO. Документация по заданным значениям объясняется так:

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

Кажется, он уже может работать в автоматическом режиме.

 nicolaas19 июн. 2017 г., 10:26
Это полностью сработало для меня. Решение Mapper.Map (модель, сущность) у меня не сработало, потому что, когда у вас есть вложенная сущность, которую вы обновляете (поэтому ваше свойство теперь ссылается на другую (уже отслеживаемую) сущность), решение Autopper будет «перезаписывать» ранее ссылаемый объект, и средство отслеживания изменений будет жаловаться, что оно уже отслеживает объект с этим идентификатором.

Ваш ответ на вопрос