[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, для этого необходимо воспользоваться тегом: