Спящий объект без первичного ключа и пустых полей - PullRequest
0 голосов
/ 05 февраля 2020

Я видел подобные случаи, но не было такого точного сочетания трудностей, и любые решения, которые я видел, не работали. Я обновляю некоторую библиотеку из Spring-data 1.X и Hibernate 4.X до Spring-data 2.X и Hibernate 5.X, и я думаю, что это связано с одной из этих двух платформ ... скорее всего, Hibernate, получая много Придирчивость к идентификаторам между версиями, потому что, по-видимому, используется @Id для нескольких полей. Я думаю, если мне нужно, могу ли я использовать Hibernate 4 с Spring-data 2, QueryDSL 4?

  1. У меня есть Hibernate @Entity на основе таблицы с 2 полями.
  2. Первое поле не является уникальным, поэтому оно не может быть PK.
  3. Другое поле может быть пустым, поэтому оно не может быть PK.
  4. Я использую Oracle в работе.
  5. Я тестирую с HSQLDB с sql .syntax_ora = true

Решение № 1: Составной ключ обоих полей.
Ошибка # 1: Используя оба решения: @ EmbeddedId / @ Embedded и @IdClass, когда обнуляемое поле равно нулю, Hibernate полностью отказывается от объекта и возвращает простой ноль вместо объекта с нулевым полем.

Решение № 2: Выбрать вместо этого псевдоколонка IE @Column(name = "ROWID")
Ошибка # 2: Hibernate не распознает, что это не настоящий столбец, и пытается выбрать его при добавлении псевдонима таблицы, что не удается, поскольку поле не найдено.

Я также пытался добавить круглые скобки "ROWID ()", но он делает то же самое. * 10 22 *

Решение № 3: Используйте @Formula, чтобы попытаться ввести фрагмент вместо поддельного @ Column
Ошибка № 3: Я думаю, что это недопустимая комбинация, а просто приводит к ошибке, говорящей identifier property [] cannot contain formula []

Решение № 4: Используйте пользовательский диалект, чтобы добавить «ROWID» в качестве ключевого слова вместо того, чтобы полагаться на его регистрацию в качестве функции
Ошибка # 4: Нет заметных отличий от решения # 2

Я не особо испортил использование JpaRepository для .findAll () в этой таблице, но в большинстве случаев я не совсем уверен, каким он должен быть. Будет ли что-то вроде # 1 работать лучше, если для ID задано значение @IdClass?

Я в полной растерянности. По сути, это устаревшая база данных, с которой я не могу связываться. Мне нужно переопределить SQL, сгенерированный для выбора объекта, функцию с частично обнуляемым составным идентификатором, функцию с неуникальным идентификатором, в противном случае использовать непостоянное поле в качестве идентификатора ... rowid / rownum / некоторый вид ха sh ... есть ли какая-то другая опция, которую я не вижу, где этот @Entity будет работать с его явно не идентифицируемой комбинацией полей?

Есть ли какой-то способ обработки нулевого значения в 2-й столбец как другое значение, когда он используется как часть идентификатора, чтобы предотвратить Сбой # 1, но все же позволяет ему быть нулевым в самом объекте?

        @Bean
        public EntityManagerFactory entityManagerFactory() {
            final LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
            //bean.setJpaDialect(new HibernateJpaDialect());
            bean.setDataSource(dataSource());
            bean.setJpaVendorAdapter(jpaVendorAdapter());
            bean.setPackagesToScan("com.company.core.domain");

            final Properties jpaProperties = new Properties();
            //jpaProperties.setProperty("javax.persistence.schema-generation.database.action", "create");
            jpaProperties.setProperty("hibernate.show_sql", "true");
            jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");

            bean.setJpaProperties(jpaProperties);
            bean.afterPropertiesSet();

            return bean.getObject();
        }
        @Bean
        public DataSource dataSource() {
            final String uuid = UUID.randomUUID().toString();
            return new EmbeddedDatabaseBuilder().addScript("schema.sql").setName(uuid + ";sql.syntax_ora=true;hsqldb.sqllog=3").build();
        }

1 Ответ

0 голосов
/ 12 февраля 2020

Лучшее, что мне удалось здесь сделать, - настроить @Entity на включение псевдостолбца ROWID. К сожалению, в то время как HSQLDB поддерживает определенный тип ROWNUM, он работает только тогда, когда НЕ предшествует префикс tableAlias, что всегда будет делать Hibernate. И это не поддерживает ROWID вообще. Но ROWID, который будет работать в Oracle, не будет работать в HSQLDB, поэтому хитрость заключается в том, чтобы вручную настроить мой встроенный HSQLDB со столбцом ROWID, установленным на автоматическое увеличение с обильными примечаниями, что это будет просто работать (TM) на Oracle без изменения модели.

Да, правильный ответ - добавить реальный ПК в таблицу в Oracle. В качестве альтернативы, использование встроенного Oracle (IE dockerized instance через test-контейнеры) также будет работать нормально, но лицензирование не особенно подходит ... или мне так сказали. НО, как бы хакерски ни было намеренно использовать другую схему в тесте, чем во время выполнения, она работает и хорошо документирована во многих местах, поэтому никто не удивляется ничему.

Или ... вы знаете. ... просто не обновляйте Hibernate. Эта сущность пропустила ошибку в более старых версиях Hibernate для YEARS, когда Mapper принял несколько полей @Id в качестве составного ключа, но Loader не распознал пустое поле как часть ключа, поэтому он позволил объекту выполнить повторную гидратацию.

...