получить идентификатор новой записи в событии SavingChanges на объектной структуре - PullRequest
2 голосов
/ 21 июля 2010

Я собираюсь реализовать некоторую общую регистрацию в entityframework 4.0, используя событие SavingChanges в контексте объекта.

Я хочу записать подробности о любых созданных / обновленных и удаленных записях, включая идентификатор изменяемой записи (который всегда является полем int identity). Во время процессов обновления и удаления я могу получить идентификатор записи, используя

    Dim AddedItems = Statemanager.GetObjectStateEntries(EntityState.Added)
    For Each entry As ObjectStateEntry In DirectCast(sender, ObjectContext).ObjectStateManager.GetObjectStateEntries(EntityState.Added)

        NewLogItem.RecordId = CInt(entry.EntityKey.EntityKeyValues(0).Value.ToString())
    Next

Но я, очевидно, не могу получить идентификатор записи, которая должна быть вставлена ​​во время вставки, потому что она еще не была записана в базу данных, есть ли простой способ обойти это?

Ответы [ 3 ]

3 голосов
/ 22 июля 2010

Один из вариантов, который вы можете сделать, - переопределить метод SaveChanges и вызвать SaveChanges к базе, не принимая изменения в объектный текст. таким образом, вы можете проверить изменения в ObjectStateManager.

 override void SaveChanges(SaveOptions)
 {
context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
//query the object statemanager

 }

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

12-1 Выполнение кода при вызове SaveChanges ()

0 голосов
/ 22 июля 2010

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

Открытая функция SaveAndLogChanges () как целое число

    Dim Statemanager As ObjectStateManager = Me.ObjectStateManager

    Dim AddedItems As IEnumerable(Of ObjectStateEntry) = Statemanager.GetObjectStateEntries(EntityState.Added)
    Dim UpdatedItems As IEnumerable(Of ObjectStateEntry) = Statemanager.GetObjectStateEntries(EntityState.Modified)
    Dim DeletedItems As IEnumerable(Of ObjectStateEntry) = Statemanager.GetObjectStateEntries(EntityState.Deleted)

    For Each entry As ObjectStateEntry In UpdatedItems
        ' dont do anything for any of the log file entries or we will end up in an infinate loop
        If (Not entry.EntitySet.Name = "LogItem" And Not entry.EntitySet.Name = "LogTransaction") Then
            createLogEntry(LogItemType.ItemType.Modify, entry)
        End If
    Next

    ' deleted entities
    For Each entry As ObjectStateEntry In DeletedItems
        ' dont do anything for any of the log file entries or we will end up in an infinate loop
        If (Not entry.EntitySet.Name = "LogItem" And Not entry.EntitySet.Name = "LogTransaction") Then
            createLogEntry(LogItemType.ItemType.Delete, entry)
        End If
    Next

    ' need to save changes here to ensure we have ids for the inserted records
    Me.SaveChanges()

    ' inserted enties
    For Each entry As ObjectStateEntry In AddedItems
        ' dont do anything for any of the log file entries or we will end up in an infinate loop
        If (Not entry.EntitySet.Name = "LogItem" And Not entry.EntitySet.Name = "LogTransaction") Then
            createLogEntry(LogItemType.ItemType.Insert, entry)
        End If
    Next

    Me.SaveChanges()

    Return iRet
End Function
0 голосов
/ 21 июля 2010

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

Возможным вариантом может быть использование факта, что одна из перегрузок метода ObjectContext SaveChanges равна virtual (или overridable в VB), а именно:

public virtual int SaveChanges(SaveOptions options)

(Примечание: это виртуально только в EF 4, а не в более ранней версии! И только эта перегрузка является виртуальной, две другие перегрузки SaveChanges - нет!)

Так что вы можете переопределить этот метод в ObjectContext вашей модели. В этом переопределенном методе вы вызываете SaveChanges базового класса, и после этого ваши новые сущности должны иметь созданные идентификаторы из базы данных, которые вы затем могли бы зарегистрировать.

(Это просто грубая идея, я никогда не тестировал и не использовал эту виртуальную перегрузку. Я создал похожий механизм ведения журнала в SavingChanges, так как вы только что внедрили его и столкнулись с той же проблемой. Но это было в EF 3.5, где этот виртуальный Метод еще не существовал. Наконец, я зарегистрировал вставки только в важных местах после вызова SaveChanges, но это, конечно, не было «универсальным», конечно. Возможно, новый виртуальный метод - хороший шанс улучшить это сейчас.)

Редактировать

Чуть точнее, что я имел в виду (в синтаксисе C #):

public partial class MyEntitiesContext : ObjectContext
{
    // ...

    public override int SaveChanges(SaveOptions options)
    {
        // Log something BEFORE entities are stored in DB

        int result = base.SaveChanges(options);

        // Log something AFTER entities are stored in DB, especially new entities
        // with auto-incrementing identity key which have been inserted in the DB
        // should have the final primary key value now

        return result;
    }

    // ...
}

Важно позвонить base.SaveChanges(options). (Вызов только SaveChanges(options) без base. заканчивается, конечно, StackOverflow.)

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