Hibernate / JPA使用提供的ID进行保存

时间:2018-11-29 18:50:24

标签: java hibernate jpa

在将实体保存到空数据库中时,是否可以使用一种简单的方法为实体使用提供的ID?

使用const std::tuple<char*, size_t> b = static_cast<const TupleConverter>(a); 调用时失败,原因是它认为该实体已分离(因为它具有ID)。出于性能原因,我不想使用EntityManager.persist(...)(它会为每个实体触发一个附加选择)。

我尝试了不同的方式,例如提供EntityManager.merge(...),但在保存之前会先将ID清空,然后触发NPE。

我还尝试提供Hibernate ForeignGenerator并覆盖其Interceptor以始终返回isTransient(),但是后来我无法正确地级联保存(或者至少我必须维护已经由我自己保留下来了)。

我认为应该有一种简单的方法来做到这一点,但找不到任何方法。

更新:添加了实体映射

true

更新:提供了其他信息

我不是手动创建实体,它们是作为数据迁移例程的一部分创建的,并且在该过程中正确设置了双向关系,因此@Entity @Data @NoArgsConstructor @EqualsAndHashCode(of = "admNr") public class Adm implements Serializable { @Id @Column(name = "ADM_NR", nullable = false) private String admNr; @OneToMany(mappedBy = "adm", cascade = CascadeType.ALL) private Set<Kunde> kundeList = new HashSet<>(); } @Entity @Data @NoArgsConstructor @EqualsAndHashCode(of = "kundeNr") public class Kunde implements Serializable { @Id @Column(name = "Kunde_Nr", nullable = false) private String kundeNr; @ManyToOne(optional = false) @JoinColumn(name = "ADM_Nr", referencedColumnName = "ADM_NR") private Adm adm; } 不可能为空。无论如何,我尝试从kunde.getAdm()中删除nullable = false,但结果是相同的。

我确实设置了级联,以便仅使用Kunde.adm即可保存整个图形,因为我不想拜访每个孩子并明确地坚持下去(我提供的模型是简化的模型,实际上有还有更多的嵌套级别。

em.persist(adm) PK是我无法摆脱的一些遗留物。

在保留图形(调用String)时出现的错误是:

em.persist(adm)

2 个答案:

答案 0 :(得分:1)

您遇到了鸡蛋问题。一方面,您有Adm并带有Kunde集和cascade = CascadeType.ALL。使用层叠时,您要求Adm实体为您保存Kunde关系,而不必设置Adm的{​​{1}}字段。因此,我假设您正在尝试不保存它们而保存它们。

Kunde

另一方面,您用 Adm adm = new Adm(); adm.setAdmNr("NO1"); Kunde kunde = new Kunde(); kunde.setKundeNr("NO1"); adm.getKundeList().add(kunde); em.persist(adm); 注释了Kunde字段,指出不允许不设置optional = false的{​​{1}}字段,上面的代码没有这样做不行因此,它给您一个非空错误。您应该在问题中提供了堆栈跟踪(的一部分)。

  

由以下原因引起:org.hibernate.PropertyValueException:not-null属性引用了null或瞬态值:model.Kunde.adm

因此,要解决此问题,请删除非空条件或设置Adm的{​​{1}}属性

Kunde

此外,正如我在上面所述,您不需要在主键上使用Adm,因为每个主键字段都是使用唯一索引禁止空值创建的。

请注意,为每个新的Kunde实例为 Adm adm = new Adm(); adm.setAdmNr("NO1"); Kunde kunde = new Kunde(); kunde.setKundeNr("NO1"); kunde.setAdm(adm); adm.getKundeList().add(kunde); em.persist(adm); 创建一个nullable = false并不是一个好主意。您拥有HashSet实体所拥有的双向映射,但是该所有权被kundeList设置所覆盖的一部分操作所覆盖。假设您要进行的查询多于更新,那么在您进行查询时,新的HashSet将始终被JPA托管列表丢弃。 Adm设置不适用于查询,因此除非您的查询明确提出要求,否则您将不会填写Kunde,并且无论如何该哈希集将替换为空的JPA托管列表。如果您只需向其中添加cascade并删除cascade设置,上述工作代码就可以正常工作。由于所有这些原因,并且可能还有更多原因,我认为最好自己亲自管理该关系,并使用kundeList作为最适合它的查询字段。

最后,使用Strings作为主键是一个非常糟糕的主意。

答案 1 :(得分:0)

问题在于模型是使用ModelMapper创建的,并且在关系的两侧提供了同一实体的不同实例。

Adm (AdmNr="1234", Java instance @1234)
  .kundeList
  -> Kunde (KundeNr="2345", Java instance @2345)
    .adm
    -> Adm (AdmNr="1234", Java instance @4444) <- should be @1234

这导致Hibernate认为Adm实体是瞬态的,并引发异常,因为从Kunde到Adm没有级联。

通过调整ModelMapper解决,因此它为一个PK提供了相同的实例。