Как получить идентификатор из сущности для Auditlog в Entity Framework 6

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

Я хочу добавить (своего рода) AudioLog при добавлении, изменении или удалении сущностей (мягкое удаление) в Entity Framework 6. Я переопределил SaveChanges, и поскольку я хочу добавить только записи журнала для EntityStates Added, Modified или Deleted, Я получаю список перед первым вызовом SaveChanges. Проблема в том, что, поскольку мне нужно регистрировать, какая операция была выполнена, мне нужно проверить EntityState сущностей. Но после вызова SaveChanges для всех записей EntityState не изменяется.

public override int SaveChanges()
{
    using (var scope = new TransactionScope())
    {
        var modifiedEntries = ChangeTracker.Entries()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Deleted || e.State == EntityState.Modified)
            .ToList();

        int changes = base.SaveChanges();
        foreach (var entry in modifiedEntries)
        {
            ApplyAuditLog(entry);
        }

        base.SaveChanges();
        scope.Complete();
        return changes;
    }
}

private void ApplyAuditLog(DbEntityEntry entry)
{
    ILog entity = entry.Entity as ILog;

    if (entity != null)
    {
        LogOperation operation;
        switch (entry.State)
        {
            case EntityState.Added:
                operation = LogOperation.CreateEntity;
                break;
            case EntityState.Deleted:
                operation = LogOperation.DeleteEntity;
                break;
            case EntityState.Modified:
                operation = LogOperation.UpdateEntity;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }

        AuditLog log = new AuditLog
        {
            Created = DateTime.Now,
            Entity = entry.Entity.GetType().Name,
            EntityId = entity.Id,
            Operation = operation,
        };

        AuditLog.Add(log);
    }
}

person baddaydaddy    schedule 05.11.2013    source источник
comment
Если идентификатор генерируется базой данных, вам необходимо получить его после вызова SaveChanges(), потому что до этого идентификатора просто не существовало.   -  person user2674389    schedule 06.11.2013
comment
Если вы посмотрите на код, я именно этим и занимаюсь. Проблема не в этом, а в изменении EntityState после SaveChanges.   -  person baddaydaddy    schedule 06.11.2013
comment
Извините, я не заметил этого. После сохранения EntityState изменится, потому что EntityState больше не добавляется и не изменяется - он не изменяется. Поэтому, если вы хотите сохранить EntityState, вы должны сохранить эти данные перед сохранением - и получить идентификатор после сохранения.   -  person user2674389    schedule 06.11.2013
comment
Это я знаю. Но я надеялся, что у кого-то есть хороший способ решить эту проблему. Поскольку у меня нет идентификатора перед SaveChanges (), я не могу понять, как сопоставить правильный идентификатор с правильным объектом AuditLog после первого SaveChanges (). Нужно ли мне полагаться на позицию индекса каждого элемента? Или есть более чистая альтернатива? Если да, то приведите пример.   -  person baddaydaddy    schedule 06.11.2013


Ответы (2)


Ааа ... Конечно !! Идентификатор будет "проблемой" только для вновь добавленных сущностей, поэтому, разделив список на два (один для измененного / удаленного и один для добавленного), я создаю AuditLog в два этапа.

Для всех, кто хочет применить этот вид AuditLog, вот мой рабочий код:

public override int SaveChanges()
{
    using (var scope = new TransactionScope())
    {
        var addedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Added).ToList();
        var modifiedEntries = ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted || e.State == EntityState.Modified).ToList();

        foreach (var entry in modifiedEntries)
        {
            ApplyAuditLog(entry);
        }

        int changes = base.SaveChanges();
        foreach (var entry in addedEntries)
        {
            ApplyAuditLog(entry, LogOperation.CreateEntity);
        }

        base.SaveChanges();
        scope.Complete();
        return changes;
    }
}

private void ApplyAuditLog(DbEntityEntry entry)
{
    LogOperation operation;
    switch (entry.State)
    {
        case EntityState.Added:
            operation = LogOperation.CreateEntity;
            break;
        case EntityState.Deleted:
            operation = LogOperation.DeleteEntity;
            break;
        case EntityState.Modified:
            operation = LogOperation.UpdateEntity;
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }

    ApplyAuditLog(entry, operation);
}

private void ApplyAuditLog(DbEntityEntry entry, LogOperation logOperation)
{
    ILog entity = entry.Entity as ILog;

    if (entity != null)
    {
        AuditLog log = new AuditLog
        {
            Created = DateTime.Now,
            Entity = entry.Entity.GetType().Name,
            EntityId = entity.Id,
            Operation = logOperation,
        };
        AuditLog.Add(log);
    }
}
person baddaydaddy    schedule 06.11.2013
comment
Вы можете заключить SaveChanges в команду try / throw, чтобы перехватить исключение и отменить записи аудита. Если фиксация не удалась, записей аудита не должно быть. - person Charles; 14.01.2014
comment
На самом деле, вам нужен идентификатор в случае добавления, аудит должен быть связан с исходной таблицей для будущего исследования. - person Costa; 08.03.2016
comment
Почему вы используете 2 foreach? вместо этого ты можешь сделать это один раз - person Faris Dewantoro; 05.01.2020

вы можете сохранить пару ключ-значение EntityState в Entity и использовать ее после первых изменений.

var entry = this.ChangeTracker.Entries () .Where (e = ›e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) .Select (e = ›Новый {e.State, e}). ToList ();

person x2da    schedule 17.04.2021
comment
Измените форматирование вашего ответа Справки по редактированию и убедитесь, что ваш вопрос отвечает на исходный вопрос авторов. - person Kwiksilver; 17.04.2021
comment
Прочтите Как ответить и обновите свой ответ. - person fartem; 18.04.2021