2010-07-21 5 views
2

Im tring для реализации некоторого общего ведения журнала в сущности 4 с использованием события SavingChanges в контексте сущности.получить идентификатор новой записи в событии SavingChanges на объектной диаграмме

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

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 

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

ответ

0

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

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

public virtual int SaveChanges(SaveOptions options) 

(Примечание: Это виртуальное только в EF- , а не в более ранней версии! И только эта перегрузка является виртуальной, другие две перегрузки 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 конечно.)

+0

Hi Slauma, Спасибо за вашу помощь, не могли бы получить, что работать, это выглядит как SaveChanges (варианты SaveOptions) может быть вызвана без параметров вызов метода SaveChanges() (который мне нужно будет вызвать из моего переопределенного метода), потому что, когда я вызывал это из моего переопределенного метода SaveChanges (SaveOptions), это привело к StackOverflowExcpetion. Однако мне удалось переосмыслить, как это сделать, в итоге я написал свой собственный метод SaveAndLogChanges. –

+0

@Julian: описанное вами StackOverflowException очень похоже на то, что вы не вызывали метод SaveChanges базового класса в своей переопределенной реализации. Я отредактировал свой ответ и добавил детали, чтобы подчеркнуть это. – Slauma

+0

Hi Public Переопределяет Функция SaveChanges (ByVal параметры, как SaveOptions) As Integer Возврат MyBase.SaveChanges (опции) End Function –

0

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

Public Function 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 
3

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

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

} 

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

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

+0

А, интересно! Мне всегда было интересно, в чем цель «AcceptAllChanges» в отличие от «SaveChanges». Теперь я вижу полезное приложение для этого метода! – Slauma

Смежные вопросы