Управление обслуживанием данных в объектных базах данных, таких как db4o.

StackOverflow https://stackoverflow.com/questions/2420248

Вопрос

Одна вещь, которую я постоянно находил очень запутанной в использовании объектной базы данных, такой как db4o это то, как вы должны обрабатывать сложные миграции, которые обычно обрабатываются SQL/PL-SQL.

Например, представьте, что у вас есть таблица в реляционной базе данных под названием my_users.Первоначально у вас был столбец с именем «полное_имя», теперь, когда ваше программное обеспечение находится в версии V2, вы хотите удалить этот столбец, разделить полные имена на пустое место и поместить первую часть в столбец с именем «первое_имя», а вторую — в столбец. с именем фамилия_фамилия.В SQL я бы просто заполнил столбцы «first_name» и «второе_имя», а затем удалил исходный столбец с именем «full_name».

Как мне это сделать в чем-то вроде db4o?Должен ли я написать программу на Java, которая будет выполнять поиск всех объектов User.class, устанавливая для полного_имени значение null и устанавливая первое_имя и последнее_имя?Когда я сделаю следующий коммит svn, не будет поля/свойства bean-компонента, соответствующего полному_имени, будет ли это проблемой?Кажется, что для использования его в производственном приложении, где меняется моя «схема», я бы хотел написать сценарий для переноса данных из версии x в версию x+1, а затем в версии x+2 фактически удалить свойства, которые я пытаюсь удалить. избавиться для версии x+1, так как я не могу написать сценарий Java для изменения свойств, которые больше не являются частью моего типа.

Кажется, что часть проблемы заключается в том, что СУБД разрешает объект, на который вы ссылаетесь, на основе простого строкового имени, нечувствительного к регистру, на таком языке, как типизация Java, более сложная, чем этот, вы не можете ссылаться на свойство, если метод получения /setter/field не является членом класса, загружаемого во время выполнения, поэтому вам по сути нужно иметь две версии вашего кода в одном и том же скрипте (хм, пользовательские загрузчики классов звучат как боль), чтобы новая версия вашего класса принадлежала другой пакет (звучит беспорядочно) или используйте стратегию версии x+1 x+2, о которой я упоминал (требует гораздо большего планирования).Возможно, есть какое-то очевидное решение, которое я никогда не почерпнул из документов db4o.

Есть идеи?Надеюсь, это имеет какой-то смысл.

Это было полезно?

Решение

Во-первых, db4o обрабатывает «простые» такие сценарии, как автоматическое добавление или удаление поля..При добавлении поля для всех существующих объектов сохраняется значение по умолчанию.Когда вы удаляете поле, данные существующего объекта все еще остаются в базе данных, и вы по-прежнему можете получить к ним доступ.Поле переименования и т. д. специальные вызовы «рефакторинга».

Теперь в вашем сценарии вы должны сделать что-то вроде этого:

  1. Удалите поле «полное_имя», добавьте новые поля «первое_имя» и «второе_имя».
  2. Перебрать все объекты «Адрес»
  3. Доступ к старому полю через API StoredClass.
  4. Разделить, изменить, обновить и т. д. значение.Установите новые значения в новом поле и сохраните объект.

Предположим, у нас есть класс «Адрес».Поле «полное_имя» было удалено.Теперь мы не хотим копировать его в «имя» и «фамилия».Тогда это могло бы выглядеть так (Java):

    ObjectSet<Address> addresses = db.query(Address.class);
    StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class);
    for (Address address : addresses) {
        String fullName = (String)metaInfoOfField.get(address);
        String[] splitName = fullName.split(" ");
        address.setFirstname(splitName[0]);
        address.setSurname(splitName[1]);
        db.store(address);
    }

Как вы предложили, вы должны написать код миграции для каждого обновления версии.Если поле больше не является частью вашего класса, вам необходимо получить к нему доступ с помощью API StoredField, как указано выше.

Вы можете получить список всех «сохраненных» классов с помощью ObjectContainer.ext().storedClasses()StoredClass.getStoredFields() вы можете получить список всех полей магазина, даже если это поле больше не существует в вашем классе.Если класс больше не существует, вы все равно можете получить объекты и получить к ним доступ через класс GenericObject.

Обновлять:Для более сложных сценариев, когда базу данных необходимо перенести за несколько этапов.

Например в версии v3 адрес-объект выглядит совершенно по-другому.Таким образом, в «скрипте миграции» для версии v1 на версию 2 больше нет необходимых полей (в моем примере имя и фамилия).Я думаю, что есть несколько возможностей справиться с этим.

  1. (Предполагая, что для этой идеи используется Java.Конечно, в .NET есть эквивалент).Вы можете сделать шаг миграции Groovy-скрипт.Чтобы каждый скрипт не мешал другому.Затем вы определяете там «классы» необходимых классов для миграции.Таким образом, каждая миграция имеет свои собственные классы миграции.С псевдонимы вы бы привязали свои классы groovy-migration к реальным Java-классам.
  2. Создание классов рефакторинга для сложных сценариев.Также свяжите эти классы с псевдонимы.

Другие советы

Здесь я рискую, потому что за свою жизнь я не рефакторил слишком много данных.

Вы делаете странное сравнение:Если вы хотите выполнить «горячую миграцию» базы данных, вам, вероятно, придется выполнить x+1, x+2 Вы описали подход к управлению версиями, но я действительно не знаю - я тоже не знаю, как это сделать с помощью SQL, поскольку я не эксперт по базам данных.

Однако если вы выполняете «холодную» миграцию, вы можете просто сделать это за один шаг, создав экземпляр нового объекта из старых данных, сохранив новый объект и удалив старый объект для каждого объекта в хранилище.Видеть ссылка на db4o.

А если честно:тот же процесс в СУБД также сложен, потому что вам придется деактивировать проверки ограничений (и, возможно, триггеры и т. д.), чтобы фактически выполнить операцию - возможно, не в приведенном вами примере, но для большинства реальных случаев. .В конце концов, разделение струн настолько простое, что выигрыша будет мало.

В SQL я бы просто заполнил столбцы «first_name» и «второе_имя».

Да, с простой операцию разделения строки, вы можете просто сделай это.Но в типичном сценарии рефакторинга вы реструктурируете объекты на основе больших и сложных наборов правил, которые сложно выразить с помощью SQL, могут потребоваться сложные вычисления или внешние источники данных.

Для этого вам также придется написать код.

В конце концов, я не вижу особой разницы в этих двух процессах.Всегда нужно быть осторожным с живыми данными, и в обоих случаях вы обязательно сделаете резервную копию.Рефакторинг — это весело, но настойчивость — это сложная задача, поэтому синхронизация в любом случае является непростой задачей.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top