ChangeLog OriginalValue такой же, как CurrentValue в EF Core Update Entity - PullRequest
1 голос
/ 21 мая 2019

У меня проблема с обновлением сущностей в EF Core и затем , регистрирующим эти изменения в таблице . Используемые технологии:

  • .NET Core 2.2.0
  • EF Core 2.2.3

Итак, я хочу получить сущность из базы данных, отредактировать ее во внешнем интерфейсе, а затем обновить в бэкэнде и сохранить эти изменения в базе данных. Кроме того, у меня есть таблица с именем ChangeLogs, где наиболее важными полями являются From (сопоставлено с OldValues) и To (сопоставлено с CurrentValues). Итак, эти два поля одинаковы (имеется в виду, что они имеют одинаковые значения, новые значения), и ситуация выглядит следующим образом:

  1. Я получаю сущность из базы данных вот так

    _context.Anomalies .Include(a => a.Asset) .FirstOrDefaultAsync(a => a.Id == anomalyId)

  2. Отредактируйте объект во внешнем интерфейсе, а затем сделайте запрос PUT для его обновления;

  3. Обновить сущность:

    Чтобы Update() заработал, сначала я должен вызвать это: _context.DetachAllEntities(); В противном случае я получаю сообщение о том, что объект с таким же Id уже отслеживается. Затем позвоните Update() и SaveChanges():

    _context.Anomalies.Update(anomaly); _context.SaveChanges();

    Объект anomaly является объектом запроса.

  4. Для части ChangeLog я переопределил метод SaveChanges(), следуя этому примеру , и значения Old / Original и New / Current установлены следующим образом: auditEntry.OldValues[propertyName] = property.OriginalValue; auditEntry.NewValues[propertyName] = property.CurrentValue;

    В основном это проходит через все записи из ChangeTracker, создает AuditEntry, а после base.SaveChanges() он возвращается и устанавливает EntityId для этого AuditEntry, потому что у вас его нет до сохранения изменений (это в Если вы добавляете новую сущность, для обновления ничего не происходит после сохранения изменений).

Метод Update () работает, изменения отражаются в базе данных. Но единственная проблема с ChangeLogs, запись из ChangeTracker.Entries() не знает OldValues.


Я признаю, что не до конца понимаю систему отслеживания, используемую EF, но полагаю, что она должна помочь мне обновлять сущности, а не создавать проблемы. Потому что я знаю, что звонить _context.DetachAllEntities(); не правильно. Я попытался использовать AsNoTracking() и сбросить DetachAllEntities(), но результат, кажется, тот же. Я думал о том, чтобы взять dbEntity, скопировать каждое поле из объекта запроса в объект базы данных, а затем Update(dbEntity), но, похоже, нужно проделать большую работу, чтобы получить небольшую выгоду. Моя сущность Anomaly имеет много навигационных свойств, поэтому было бы сложно создать для нее метод копирования и сохранить его.

DetachAllEntities() определяется следующим образом:

public static void DetachAllEntities(this DbContext context)
{
    var entries = context.ChangeTracker.Entries().ToList();
    foreach (var entry in entries)
    {
        entry.State = EntityState.Detached;
    }
}

DbContext установлен на Scoped срок службы, менеджеры также.

Я пытался использовать метод Auditing из этого урока , но результат тот же.

У меня есть опасение, что весь процесс обновления не выполнен правильно, и поэтому возникают проблемы ..

UPDATE Я создал пример проекта, чтобы проиллюстрировать эту проблему. Вы можете проверить исходный код на bitbucket . У README есть еще информация об этом

Я сериализовал объекты, извлеченные из контекста.

С отслеживанием на левом <====> Без отслеживания на правом image With NO tracking on the RIGHT">

Любые советы, мнения, новые идеи, комментарии приветствуются. Спасибо!

Ответы [ 2 ]

2 голосов
/ 22 мая 2019

enter image description here

Я думаю, что ваша проблема здесь. Поскольку два объекта существуют в разных контекстах, это принципиально другой объект. Если вы измените свой код так, чтобы вы извлекали сущность из базы данных, обновляли ее значения, а затем использовали этот объект для передачи в метод SaveChangesAndAudit (). Вы получите ожидаемый результат. Я скорректировал код на прилагаемом скриншоте. Вы также столкнетесь с фундаментальной проблемой, с которой сталкивается большинство разработчиков, а именно с сопоставлением объектов - такими инструментами, как Automapper, которые делают вашу жизнь проще с такими вещами - поэтому, если ваши сущности большие, стоит взглянуть на это, чтобы помочь; -)

https://github.com/AutoMapper/AutoMapper

1 голос
/ 22 мая 2019

При использовании EF сущности создаются / заполняются «отслеживающей» информацией, которая связывает сущность с контекстом (и другими вещами).

Чтобы обновить сущность, все, что вам нужно сделатьэто запрос объекта из контекста, измените значения и затем вызовите savechanges.Нет необходимости отсоединять сущности (если у вас нет для этого особой причины).

Следующий пример - это все, что вам нужно для обновления сущности.

EX:

    var anomly = _context.Anomalies
     .Include(a => a.Asset)
     .FirstOrDefaultAsync(a => a.Id == anomalyId);

    anomly.Description = "I have changed the description";

    _context.SaveChanges();

РЕДАКТИРОВАТЬ

Если вы закроете контекст или отсоедините его, вам потребуется запросить сущность и обновить ее с помощьюновые значения перед вызовом savchanges.

EX:

var anomly = _context.Anomalies
 .Include(a => a.Asset)
 .FirstOrDefaultAsync(a => a.Id == anomalyId);

anomly.Description = "I have changed the description";

_context.Dispose();

_context = new DBContext();

var databaseAnomoly = _context.Anomalies
 .Include(a => a.Asset)
 .FirstOrDefaultAsync(a => a.Id == anomaly.Id);

//Update fields
databaseAnomoly.Description = anomly.Description;

_context.SaveChanges();
...