logo

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

<script name="fixTask">
      <text>
        UPDATE TaskBase SET Executor = 2 WHERE id = 1
      </text>
</script>

Дополнительные параметры, используемые в теге <method/>, также можно применить и к тегу <script>.

Ссылки на элементы API

Прикрепленные файлы