在将实体保存到空数据库中时,是否可以使用一种简单的方法为实体使用提供的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)
答案 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提供了相同的实例。