Это немного проблематично, и я надеюсь, что вы найдете эту сложную проблему такой же интересной, как и я ...:)
У меня есть подкласс DataContext
, называемый MyDataContext
, в котором я переопределил метод SubmitChanges()
с помощью некоторого кода вида:
BeginTransaction(); // my own implementation
IList<object> Updates = GetChangeSet().Updates;
foreach (object obj in Updates) {
MyClass mc = obj as MyClass;
if (mc != null)
mc.BeforeUpdate(); // virtual method in MyClass to allow pre-save processing
}
// This is followed by similar code for the Deletes and Inserts, then:
base.SubmitChanges();
// Then do post-save processing...
foreach (object obj in Updates) {
MyClass mc = obj as MyClass;
if (mc != null)
mc.AfterUpdate(); // virtual method in MyClass to allow post-save processing
}
// similar code for Inserts and Deletes
// ...
CommitTransaction();
// obviously all enclosed in a try-catch block where the catch does a rollback
Пока все хорошо. Но есть небольшая проблема, которая возникает, если реализация MyClass
вызывает SubmitChanges()
в своем методе BeforeUpdate()
или AfterUpdate()
. Теперь у нас есть рекурсия, которая может привести к переполнению стека.
Один из способов обойти это - иметь переменную, блокирующую рекурсию, в начале SubmitChanges()
. Но что делать, если сохранение заблокировано? Я не могу раскрутить это в новую ветку; вызывающий поток может потребовать, чтобы вызов SubmitChanges()
был синхронным, например, если ему нужен доступ к свойству авто-номера сразу после сохранения.
Дополнительный фактор, который необходимо учитывать, заключается в том, что если какие-либо объекты изменяются в ходе предварительной или последующей обработки, я также хочу, чтобы были вызваны их BeforeSave()
и AfterSave()
методы.
Есть ли какой-нибудь умный способ сделать все это аккуратно и правильно?