[ELMA3] Преобразование базы данных с помощью XML-файла структуры
В статье приведен пример преобразования базы данных при помощи XML-файла структуры, в котором переносятся значения объекта из одной колонки (тип данных целое число) в другую (тип данных строка).
Методы базового класса DbStructureExtension
/// <summary> /// Uid провайдера БД /// </summary> public abstract Guid ProviderUid /// <summary> /// Структура /// </summary> public virtual DbStructure Structure /// <summary> /// Версия (по умолчанию - версия сборки, в которой находится текущий класс) /// </summary> public virtual Version Version /// <summary> /// Родительский преобразователь (для провайдеров конкретных СУБД) /// </summary> public virtual Type Parent /// <summary> /// Ссылки на преобразователи БД, от которых зависит данный преобразователь /// </summary> public virtual Type[] References /// <summary> /// Сборка, внутри которой находится ресурс со структурой (по умолчанию - сборка текущего класса) /// </summary> protected virtual Assembly Assembly /// <summary> /// Имя файла со структурой в ресурсах сборки (по умолчанию соответствует имени текущего класса, и дописывается расширение .xml) /// </summary> protected virtual string ResourceFileName
Пример реализации класса DbStructureExtension
[Component] internal class MyModuleDbStructureCs : DbStructureExtension { public override Guid ProviderUid { get { return Guid.Empty; } //Если нужно для определенной базы, например, для Firebird, то можно воспользоваться FirebirdProvider.UID } public void MoveColumn() { const string tableName = "CALLS"; const string newColumn = "KOLICHESTVOZVONKOV"; string oldColumn = Locator.GetServiceNotNull<DbModelUpdater>().GetDeletingColumnTemporaryName(tableName, newColumn); //Старая колонка //переименовывается перед удалением, поэтому нужно получить её переименованное имя, //затем переписать данные в новую колонку, затем она удалится var transformationProvider = Locator.GetServiceNotNull<ITransformationProvider>(); if (transformationProvider.ColumnExists(tableName, newColumn) && transformationProvider.ColumnExists(tableName, oldColumn)) { transformationProvider.ExecuteNonQuery(string.Format( "UPDATE {0} SET {1} = CAST({2} as varchar(255))", transformationProvider.Dialect.QuoteIfNeeded(tableName), transformationProvider.Dialect.QuoteIfNeeded(newColumn), transformationProvider.Dialect.QuoteIfNeeded(oldColumn))); } } }
В примере в объекте CALLS было свойство KOLICHESTVOZVONKOV с типом данных Целое число, в системе были добавлены записи в объект, затем потребовалось свойство KOLICHESTVOZVONKOV с типом данных Строка вместо старого свойства. Для этого в объекте старое свойство удаляется и создается точно такое же новое (отображаемое имя, имя свойства и имя поля в БД остались прежними) с типом данных Строка. В процессе преобразования базы данных старая колонка в базе данных переименовывается, затем удаляется. Между этими событиями выполняется вышеуказанный код.
Для преобразования базы данных необходим файл в формате .xml, с названием (по умолчанию), как у класса, наследуемого от DbStructureExtension. Реализация точки расширения и xml должны лежать в одном месте, а также у xml должен быть установлен Build Action – Embedded Resource:
Рис. 1. Расположение файлов MyModuleDbStructureCs.cs и MyModuleDbStructureCs.xml
В данном примере названием файла xml является: MyModuleDbStructureCs.xml. Пример кода:
<?xml version="1.0" encoding="utf-8" ?> <root uid="{3B204C3F-B611-4fc3-A859-AAD3F355CE71}"> <methods> <method name="MoveColumn" ExecuteTime="OnTablesDeleting"/> </methods> </root>
При перезапуске сервера (после активации модуля) система будет искать файл .xml с названием класса, наследуемого от DbStructureExtension, затем, в xml-файле по тегам <method name="" /> будут определены названия методов, которые необходимо выполнить для преобразования базы данных. Как можно заметить, в реализации класса используется метод CreateDefaultFilters, поэтому он указан в файле xml в соответствующем теге. Необходимо располагать класс преобразования БД в одном месте, где и xml.
У тегов <method/> существуют дополнительные параметры, пример использования: <method name="DataSecondPassConverting" ExecuteTime="OnTablesDeleted" AlwaysExecute="true" />
Параметры:
Параметр |
Значение параметра |
Описание |
ExecuteTime |
OnBeforeStart |
Перед началом преобразования (выполняется в отдельной транзакции) |
OnStart |
Начало преобразования |
|
OnTriggersDeleted |
После удаления триггеров |
|
OnProceduresDeleted |
После удаления процедур |
|
OnViewsDeleted |
После удаления представлений |
|
OnIndexesDeleted |
После удаления индексов |
|
OnForeignKeysDeleted |
После удаления внешних ключей |
|
OnPrimaryKeysDeleted |
После удаления первичных ключей |
|
OnTablesCreating |
Перед созданием таблиц и колонок |
|
OnTablesCreated |
После создания таблиц и колонок |
|
OnTablesDeleting |
Перед удалением ненужных таблиц и колонок |
|
OnTablesDeleted |
После удаления ненужных таблиц и колонок |
|
OnForeignKeysCreated |
После создания внешних ключей |
|
OnPrimaryKeysCreated |
После создания первичных ключей |
|
OnIndexesCreated |
После создания индексов |
|
OnViewsCreated |
После создания представлений |
|
OnProceduresCreated |
После создания процедур |
|
OnTriggersCreated |
После создания триггеров |
|
OnComplete |
После завершения преобразования |
|
AlwaysExecute |
True/false |
|
OnDeactivate |
True/false |
Выполнять при деактивации модуля |
Также в данной xml можно использовать запросы SQL, для этого необходимо воспользоваться тегом: