При реализации собственных обработчиков события XafApplication.SetupComplete необходимо учитывать особенность работы утилиты DBUpdater из стандартной поставки DevExpress XAF.

Когда в коде обработчиков  событий XafApplication.SetupComplete без соблюдения определенных мер предосторожности выполняются обращения к базе данных, складывается ситуация, в которой базу данных приложения становится невозможно обновить с помощью утилиты DBUpdater. В ходе обновления БД будет возникать исключение о несоответствии версий БД и приложения. Т.е. то самое исключение, для устранения которого и используется утилита DBUpdater.

В  данной статье описываются причины и возможные способы решения проблемы.

Причины кроются в способе, которым утилита DBUpdater выполняет обновление БД. Утилита DBUpdater с помощью механизмов reflection выполняет поиск класса, являющегося наследником DevExpress.ExpressApp.XafApplication в указанном приложении. Затем  она создает экземпляр найденного класса и вызывает метод Setup экземпляра. Методу Setup в качестве параметров передается строка подключения к БД и список модулей, указанный в узле “Modules” конфигурационного файла приложения. Затем вызовом CreateDatabaseUpdater() на экземпляре приложения создается экземпляр DatabaseUpdater и, если это необходимо, вызывается его метод Update():

Из приведенного кода видно, что обновление базы данных (вызов метода dbUpdater.Update()) выполняется после вызова application.Setup(). Событие же SetupComplete генерируется в коде метода Setup() в самом конце его выполнения. Таким образом, если в обработчике события SetupComplete выполняется обращение к несовместимой базе данных (точнее, попытка создать ObjectSpace вызовом XafApplication.CreateObjectSpace()), то тут же будет выброшено исключение о несоответствии версий БД и приложения, и строка  dbUpdater.Update() кода утилиты DBUpdater не будет выполнена. Базу данных становится невозможно обновить.

Чтобы избежать данной проблемы можно перед обращением к базе данных в обработчике события  проверять ее на совместимость с помощью метода CheckCompatibility() экземпляра класса DatabaseUpdater.  Обращение к базе данных выполнять только в том случае, если она полностью совместима с приложением.  Для выполнения такой проверки создан вспомогательный статический класс Xafari.Utils. DatabaseHelper с методом  static bool IsDatabaseCompatible(XafApplication application). Данный статический метод возвращает True, если проверка на совместимость базы данных и приложения успешно пройдена.

Пример одного из таких обработчиков события:

Когда же требуется запись данных в базу не только при запуске приложения, но и при обновлении базы данных, то код обращения к базе нужно вызывать из двух мест:

  1. Из обработчика события SetupComplete, c соблюдением описанных мер предосторожности – для обычного режима функционирования приложения;
  2. Из перекрытого в наследнике класса ModuleUpdater метода UpdateDatabaseAfterUpdateSchema – для случая обновления базы данных.