没有主键和可为空字段的休眠实体

Hibernate Entity with no Primary Key and nullable fields

我见过类似的案例,但不是这种困难的确切组合,而且我见过的任何解决方案都没有奏效。我正在将一些库从 Spring-data 1.X 和 Hibernate 4.X 升级到 Spring-data 2.X 和 Hibernate 5.X 我认为这个与这两个框架之一有关......可能是 Hibernate,对版本之间的 ID 越来越挑剔,因为在多个字段上打 @Id 似乎曾经有效。我想如果需要的话,我可以将 Hibernate 4 与 Spring-data 2、QueryDSL 4 一起使用吗?

  1. 我有一个基于具有 2 个字段的 table 的 Hibernate @Entity。
  2. 第一个字段不唯一,所以不能作为主键。
  3. 其他字段可以为空,所以不能作为主键。
  4. 我在生产中使用 Oracle。
  5. 我正在使用 HSQLDB 进行测试 sql.syntax_ora=true

解决方案 #1:两个字段的组合键。
失败#1:同时使用@EmbeddedId/@Embedded 和@IdClass 解决方案,当可空字段为空时,Hibernate 完全放弃该对象,returns 一个简单的空而不是具有空字段的对象。

解决方案 #2:Select 使用伪列代替 IE @Column(name = "ROWID")
失败 #2:Hibernate 无法识别这不是真正的列,并在添加 table 别名时尝试 select 它,但由于未找到该字段而失败。

我也试过添加括号 "ROWID()" 但效果相同。

解决方案 #3:使用 @Formula 尝试注入代码片段而不是伪造的 @Column
失败 #3:我认为这不是允许的组合,只会导致错误 identifier property [] cannot contain formula []

解决方案 #4:使用自定义方言将 "ROWID" 添加为关键字,而不是依赖于将其注册为函数
失败 #4:没有 table 与解决方案 #2

的区别

我并没有真正弄乱用于此 table 上的 .findAll() 的 JpaRepository,但在大多数情况下我不确定它应该是什么。如果将 ID 设置为 @IdClass,#1 之类的东西会更好吗?

我在这里完全不知所措。它实际上是一个我不能真正搞砸的遗留数据库。我需要覆盖生成为 select 对象的 SQL,具有部分可为空的复合 ID 的函数,具有非唯一 ID 的函数,否则使用非持久字段作为 id...rowid/rownum/some 有点像哈希...是否还有其他选项我没有看到这个@Entity 将在哪里使用其明显无法识别的字段组合?

当第 2 列中的空值用作 ID 的一部分以防止失败 #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();
        }

我在这里设法做的最好的事情是调整我的@Entity 以包含 ROWID 伪列。不幸的是,虽然 HSQLDB 支持某种类型的 ROWNUM,但它仅在不以 tableA​​lias 为前缀时才有效,而 Hibernate 将始终这样做。而且它根本不支持 ROWID。但是可以在 Oracle 中使用的 ROWID 不能在 HSQLDB 中使用,所以技巧是手动设置我的嵌入式 HSQLDB,将 ROWID 列设置为自动递增,并附上大量注释,这将在 Oracle 上运行,无需修改模型.

是的,正确答案是给Oracle中的table加上一个真正的PK。或者使用嵌入式 Oracle(通过测试容器的 IE dockerized 实例)也可以正常工作,但许可并不是特别适合……或者有人告诉我。但是,尽管在测试中故意使用不同于运行时的模式,但它确实有效并且在多个地方都有详细记录,所以没有人对任何事情感到惊讶。

或者...您知道...只是不要升级 Hibernate。这个实体在旧版本的 Hibernate 中偷偷发现了多年的错误,其中 Mapper 接受多个 @Id 字段作为复合键,但 Loader 没有将空字段识别为键的一部分,因此它允许对象重新水化。