1

当合并不会分配 @Id 变量时,JPA2 中是否存在特定情况?然而返回一个新的实体实例而不触发异常?

假设我有这个层次结构:

@MappedSuperclass
abstract class Bar {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  ...
}

@Entity
@Table(name = "BAR_1S")
@Access(AccessType.PROPERTY)
class Bar1 extends Bar {
  ...
}

@Entity
@Table(name = "BAR_2S")
@Access(AccessType.PROPERTY)
class Bar2 extends Bar {
  ...
}

由于尚未找到原因,Bar1 的实例在 merge() 之后获得了一个 id,而 Bar2 的实例没有。至少它看起来是这样的。我一直在尝试各种方法,但都没有成功。

看起来 Hibernate (4.1.4.Final) 不想为该特定类的实例分配 id。:-)

我的问题:

  • 有人有过这样的事情吗?

  • 有人可以告诉我在 Hibernate 中的哪个位置设置了 ID 吗?所以我可以调试那部分代码并找出它为什么会跳过分配。IntelliJ 似乎并没有打破实体中字段的修改。

编辑 - 环境配置

  • 操作系统:LMDE amd64
  • 数据库:MySQL (5.1.61-2) ConnectJ (5.1.17)
  • JVM:1.7.0_04
  • 休眠:4.1.4.Final
  • 春天:3.1.1

编辑 - 代码

所有实体类都是 Bar 的(内)直接子类。只有一个地方定义了@Id。并且有一些相同的 Bar2 案例确实获得了 id。但特别是 Bar2 没有。

最终 Bar1 bar = new Bar1(); JpaTemplate.merge(bar); <-- 得到一个 id

最终 Bar2 bar = new Bar2(); JpaTemplate.merge(bar); <-- 没有id

该应用程序使用 Spring 的 JpaTemplate 来合并实体。对于该特定类的所有例外情况,它都可以正常运行。

所以,如果我能找到分配 id 的 Hibernate 类,我可能会发现我忽略了哪些愚蠢的细节。:-)

4

2 回答 2

0

首先注意: JpaTemplate 已弃用,不应再使用。它只是委托给 EntityManager 的merge()方法,并且都返回一个实体。

以下是 JPA 规范关于合并的内容:

如果 X 是一个新的实体实例,则创建一个新的托管实体实例 X',并将 X 的状态复制到新的托管实体实例 X'。

因此,如果生成了 ID,它将分配给附加的实体,而不是您传递给 merge 方法的对象。因此,您永远不应该忽略 merge 方法的结果。代替

jpaTemplate.merge(bar);

你应该做:

bar = jpaTemplate.merge(bar);

此外,JPA 规范还说

在数据库插入发生之前,不能保证生成的 id 可用。

这可能是您没有身份证的另一个原因。AFAIK,使用 MySQL 的 AUTO 策略,依赖于数据库中的自动增量 ID 列,并且只有在插入完成后才能获取 ID 的值,并且 Hibernate 一直等到绝对需要刷新,因此执行插入。如果您确实需要在合并后立即拥有 ID,请执行以下操作:

bar = jpaTemplate.merge(bar);
jpaTemplate.flush();
Long id = bar.getId();
于 2012-06-04T17:05:01.117 回答
0

找到了 !合并发生在@Transactional 注释的重载方法中。我假设重载方法将“继承”注释。显然情况并非如此。

通过使用 @Transactional 注释重载方法,它似乎可以工作。

知道这将是一件愚蠢的事情......

于 2012-06-06T16:45:07.923 回答