Используйте AsNoTracking для сущностей, сопоставленных с AutoMapper - PullRequest
0 голосов
/ 01 марта 2019

У меня есть ситуация, когда я сопоставляю DTO -> Database Entity с помощью automapper.

var entityObj = _mapper.Map<REQUESTEXT>(reqDTO);

Затем я использую entityObj для обновления записи в базе данных.

void Update(REQUESTEXT entityObj)
{
    _context.REQUESTEXTs.Attach(entityObj);  <--- Error
    _context.Entry(entityObj).Property(x => x.CUSTOPTIONCD).IsModified = true;
    _context.SaveChanges();
}

Когда я пытаюсь присоединить REQUESTEXT объект к контексту, он выдает мне ошибку:

Не удалось присоединить объект типа «А», поскольку другой объект того же типа уже имеет тот жезначение первичного ключа.Это может произойти при использовании метода «Присоединить» или установке состояния объекта на «Неизменено» или «Изменено», если какие-либо объекты в графе имеют конфликтующие значения ключей.Это может быть потому, что некоторые объекты являются новыми и еще не получили сгенерированные базой данных значения ключей.В этом случае используйте метод «Добавить» или «Добавленный» объект сущности для отслеживания графика, а затем установите для состояния не новых объектов «Неизмененный» или «Измененный» в зависимости от ситуации.

Согласно этому SO ответу: https://stackoverflow.com/a/23228001/1169180 Мне нужно использовать AsNoTracking(), я не уверен, как использовать это в AutoMapper?

Есть предложения?

1 Ответ

0 голосов
/ 01 марта 2019

AsNoTracking означает, что объекты загружаются контекстом, а не Automapper.Вы получаете ошибку, потому что в какой-то момент в жизни этого DbContext он загрузил сущность с этим идентификатором и отслеживает ее.Опция, которую они рекомендовали, состоит в том, чтобы изменить загрузку вашей сущности, чтобы использовать AsNoTracking, который эффективно сообщает EF , а не , чтобы отслеживать сущность, когда она читается.

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

Например:

var existingEntity = _context.REQUESTEXTs.Local.SingleOrDefault(x => x.EntityId == reqDTO.EntityId);
if(existingEntity != null)
    mapper.Map(reqDto, existingEntity);
else
{
    var entityObj = _mapper.Map<REQUESTEXT>(reqDTO);    
    _context.REQUESTEXTs.Attach(entityObj);
    _context.Entry(entityObj).Property(x => x.CUSTOPTIONCD).IsModified = true;
} 
_context.SaveChanges();

Это проверяет локальный кеш на наличие существующей сущности (не затрагивает БД) и, если найден, использует AutoMapper для обновления своих свойств.Отслеживание сущности запишет изменения, поэтому при вызове SaveChanges изменения будут переданы в БД.Если в локальном кэше нет сущности, то мы создаем новый экземпляр, присоединяем его, помечаем как измененный и сохраняем.

Одно предложение, которое, по-видимому, отсутствует в вашем примере: Вы должны проверитьпредположения о том, что:

  • ID в вашем DTO действительно существует в базе данных, прежде чем пытаться это сделать, и
  • Изменяемая запись может и должна редактироваться пользователем, выполняющим этот запрос.и
  • Обновляемые данные полностью проверены.

Если это веб-приложение / w с доступным действием контроллера или конечной точкой веб-API, это может быть использовано, чтобы позволить пользователям редактироватьзаписи, которые они иначе не должны иметь, или обновлять записи так, как они не должны.(Ничего не доверяйте клиентскому запросу.) Каждый запрос должен быть тщательно проверен, и любое обнаруженное отклонение должно завершить сеанс клиента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...