Сопоставить столбец1, столбец2, столбецN базы данных с коллекцией элементов.

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

Вопрос

В устаревших таблицах базы данных мы имеем пронумерованные столбцы, такие как C1, C2, C3, C100 или M1, M2, M3, M100.
Эти столбцы представляют данные BLOB.

В этой базе данных ничего изменить невозможно.

Используя JPA Embeddable, мы сопоставляем все столбцы с отдельными полями.А затем во время внедрения мы переопределяем имена, используя 100 аннотаций переопределения.

Недавно мы перешли на Hibernate, и я нашел такие вещи, как Пользовательскаяколлекциятипе и Композитеусертипе.Но я не нашел ни одного варианта использования, близкого моему.

Можно ли реализовать какой-либо тип пользователя с помощью Hibernate, чтобы иметь возможность сопоставлять набор столбцов с коллекцией? без дополнительных запросов?

Редактировать:
Как вы, наверное, заметили, названия столбцов могут отличаться от таблицы к таблице.Я хочу создать один тип, например «LegacyArray», без необходимости указывать все @Columns каждый раз, когда я использую этот тип.Но вместо этого я бы использовал

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "A"),
      @Parameter(name = "size", value = "128")
   })
   List<Integer> legacyA;

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "B"),
      @Parameter(name = "size", value = "64")
   })
   List<Integer> legacyB;
Это было полезно?

Решение

Я могу придумать несколько способов, которыми я мог бы это сделать.

1.Создайте представления для информации о коллекции, имитирующие нормализованную структуру таблицы, и сопоставьте ее с Hibernate как коллекцию:

Предполагая, что ваша существующая таблица называется primaryentity, я бы создал представление, подобное следующему:

-- untested SQL...
create view childentity as
(select primaryentity_id, c1 from primaryentity union
select primaryentity_id, c2 from primaryentity union
select primaryentity_id, c3 from primaryentity union
--...
select primaryentity_id, c100 from primaryentity)

Теперь с точки зрения Hibernate, childentity это просто нормализованная таблица, имеющая внешний ключ для primarykey.Сопоставление этого должно быть довольно простым и описано здесь:

Преимущества этого подхода:

  • С точки зрения Hibernate, таблицы нормализованы, это довольно простое сопоставление.
  • Никаких обновлений существующих таблиц.

Недостатки:

  • Данные доступны только для чтения, я не думаю, что ваше представление может быть определено обновляемым образом (я могу ошибаться)
  • Требуется изменение базы данных, возможно, вам придется создать множество представлений.

Альтернативно, если ваш администратор базы данных даже не позволяет вам добавить представление в базу данных или вам нужно выполнить обновления:


2.Используйте Hibernate средство отображения динамической модели чтобы сопоставить свойства C1, C2, C3 с карта, и напишите код, который вам нужен ДАО Layer выполните соответствующий диалог между свойством Map и Collection:

Я никогда этого не делал, но считаю, что Hibernate позволяет сопоставлять таблицы с HashMaps.Я не уверен, насколько динамически Hibernate позволяет вам это делать (т. е. можно ли обойтись простым указанием имени таблицы и автоматическим сопоставлением всех столбцов Hibernate?), но я могу придумать еще один способ сделать это.

Однако, если вы используете этот подход, обязательно используйте объект доступа к данным шаблон и убедитесь, что внутренняя реализация (использование HashMaps) скрыта от клиентского кода.Также обязательно проверяйте перед записью в базу данных, чтобы размер вашей коллекции не превышал количество доступных столбцов.

Преимущества этого подхода:

  • Никаких изменений в базе данных вообще
  • Данные обновляются
  • Сопоставление O/R относительно просто.

Недостатки:

  • Множество сантехники в слое DAO для сопоставления соответствующих типов.
  • Использует экспериментальные функции Hibernate, которые могут измениться в будущем.

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

Лично я думаю, что дизайн звучит так, будто он ломается. первая нормальная форма для реляционных баз данных.Что произойдет, если вам понадобится C101 или M101?Снова изменить схему?Я думаю, это очень навязчиво.

Если вы добавите Hibernate, ситуация станет еще хуже.Добавление C101 или M101 означает необходимость изменения ваших объектов Java, отображений Hibernate и всего остального.

Если у вас есть отношения 1:m с таблицами C и M, вы сможете справиться с случаями, которые я только что привел, добавив дополнительные строки.Ваши объекты Java содержат Collection<C> или Collection<M>.Ваши сопоставления Hibernate — это один ко многим, которые не меняются.

Возможно, причина того, что вы не видите ни одного примера Hibernate, подходящего для вашего случая, заключается в том, что этот дизайн не рекомендуется.

Если вам нужно, возможно, вам стоит посмотреть Сопоставление компонентов Hibernate.

ОБНОВЛЯТЬ:Тот факт, что это наследие, отмечен должным образом.Я хочу привести первую нормальную форму как для тех, кто может найти этот вопрос в будущем, так и для человека, разместившего этот вопрос.Мне бы не хотелось отвечать на вопрос так, чтобы молча утверждать эту конструкцию как «хорошую».

Упоминание о сопоставлении компонентов Hibernate уместно, поскольку знание названия того, что вы ищете, может быть ключевым моментом при поиске.Hibernate позволяет сделать объектную модель более детальной, чем реляционная модель, которую она отображает.Вы можете моделировать денормализованную схему (например, объекты «Имя» и «Адрес» как часть более крупного объекта «Человек»).Именно так называют такую ​​технику.Возможно, это поможет найти и другие примеры.

Извините, если я неправильно понял вашу проблему, я мало что знаю о Hibernate.Но не могли бы вы просто объединить выборку из базы данных, чтобы получить что-то вроде того, что вы хотите?

Нравиться:

SELECT whatever
     , C1||C2||C3||C4||...||C100 AS CDATA
     , M1||M2||M3||M4||...||M100 AS MDATA
FROM ...
WHERE ...

(Разумеется, оператор конкатенации в разных СУБД различается.)

[EDIT] Я предлагаю использовать CompositeUserType. Вот пример.Также есть хороший пример на странице 228f в книге «Сохранение Java в Hibernate».

Это позволяет вам обрабатывать множество столбцов как один объект в Java.

Отображение выглядит следующим образом:

@org.hibernate.annotations.Columns(columns = {
    @Column(name="C1"),
    @Column(name="C2"),
    @Column(name="C3"),
    ...
})
private List<Integer> c;

Hibernate загрузит все столбцы одновременно во время обычного запроса.

В вашем случае вы должны скопировать значения int из списка в фиксированное количество столбцов в nullSafeSet.Псевдокод:

for (int i=1; i<numColumns; i++)
    if (i < list.size())
        resultSet.setInt(index+i, list.get(i));
    else
        resultSet.setNull(index+i, Hibernate.INTEGER.sqlType());

В nullSafeGet вы должны создать список и прекратить добавление элементов, когда столбец имеет значение NULL.Для дополнительной безопасности я предлагаю создать собственную реализацию списка, которая не позволяет выходить за пределы количества столбцов (наследовать от ArrayList и переопределить ensureCapacity()).

[EDIT2] Если вы не хотите вводить все аннотации @Column, используйте для них генератор кода.Это может быть так же просто, как сценарий, которому вы даете имя и номер, и он печатает @Column(...) в System.out.После запуска скрипта просто вырежьте и вставьте данные в источник.

Единственным другим решением было бы получить доступ к внутреннему API Hibernate для создания этой информации во время выполнения, но этот API является внутренним, поэтому многие вещи являются конфиденциальными.Вы можете использовать отражение Java и setAccessible(true) но этот код, вероятно, не переживет следующее обновление Hibernate.

Вы можете использовать UserTypes для сопоставления заданного количества столбцов с любым типом по вашему желанию.Это может быть коллекция, если (например) коллекции всегда ограничены по размеру известным количеством элементов.

Прошло много времени (> 3 лет) с тех пор, как я использовал Hibernate, поэтому я довольно заржавел, но помню, что это было очень легко сделать;твой BespokeUserType класс сдал экзамен ResultSet к гидрат ваш объект из него.

Я тоже никогда не использовал Hibernate.

Я предлагаю написать небольшую программу на интерпретируемом языке (например, Питон), в котором вы можете выполнить строку, как если бы это была команда.Вы можете создать оператор, который избавит вас от утомительной работы по выполнению того, что вы хотите, вручную.

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