我有一个我无法理解的问题,也没有找到任何真正的解决方案。我有一个对象模型,其中一个类中有一堆集合,这些集合的对象中还有其他实体。所有这些集合都将使用一对多JoinColumn进行连接。
使用调度程序,“Mother”对象将在其集合中获取新值,或者集合的现有对象将更新,最后应将新状态写入数据库。
我遇到的问题是,集合中的对象不会获得JPA Eclipselink返回的ID,因此重复的条目将存在于数据库中。我不知道如何解决这个问题,我希望有人可以帮助我。
在下面的代码中,您将看到一个重现故障的小示例程序。通过创建三个工厂和三个事务来模拟调度程序调用。在第一个和第二个之间,集合将被更改,因此将发生两个树重复条目。如果你添加另一个圆形而不是另一个元素将插入表“adresse”。
班级主要:
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import de.testpackage.adresse;
import de.testpackage.people;
import de.testpackage.register;
public class Main {
public static void main(String[] args) {
// Create Set for people
register r = new register();
// Initial Loading Person 1
people p = new people();
p.setName("Person1");
p.setZahl(10);
adresse a = new adresse();
a.setAdresse("Adresse11");
p.getAdresse().add(a);
adresse b = new adresse();
b.setAdresse("Adresse12");
p.getAdresse().add(b);
r.addPerson(0, p);
people p2 = new people();
p2.setName("Person2");
p2.setZahl(10);
adresse a2 = new adresse();
a2.setAdresse("Adresse21");
p2.getAdresse().add(a2);
adresse b2 = new adresse();
b2.setAdresse("Adresse22");
p2.getAdresse().add(b2);
r.addPerson(1, p2);
// Simulation of a Timertask first repeat
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
System.err.println("Before:" + r.getId());
em.getTransaction().begin();
if (r.getId() == null){
em.persist(r);
} else {
em.merge(r);
}
em.getTransaction().commit();
em.close();
System.err.println("After 1:" + r.getId());
// Adding Adressse people1
adresse c = new adresse();
c.setAdresse("Adresse23");
r.getListpeople().get(1).getAdresse().add(c);
// Simulation of a Timertask second repeat
EntityManagerFactory factory2 = Persistence.createEntityManagerFactory("test");
EntityManager em2 = factory.createEntityManager();
em2.getTransaction().begin();
if (r.getId() == null){
em2.persist(r);
} else {
em2.merge(r);
}
em2.getTransaction().commit();
em2.close();
// Simulation of a Timertask third repeat
EntityManagerFactory factory3 = Persistence.createEntityManagerFactory("test");
EntityManager em3 = factory.createEntityManager();
em3.getTransaction().begin();
if (r.getId() == null){
em3.persist(r);
} else {
em3.merge(r);
}
em3.getTransaction().commit();
em3.close();
}
}
班级注册
package de.testpackage;
import ......
@Entity
public class register {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "register_fk")
Map<Integer, people> Listpeople = new HashMap<>();
public void addPerson(int i, people p){
this.Listpeople.put(i,p);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Map<Integer, people> getListpeople() {
return Listpeople;
}
}
班级人员
package de.testpackage;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
@Entity
public class people {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private int zahl;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "people_fk")
private Set<adresse> adresse = new HashSet<>();
public people() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getZahl() {
return zahl;
}
public void setZahl(int zahl) {
this.zahl = zahl;
}
public Long getId() {
return id;
}
public Set<adresse> getAdresse() {
return this.adresse;
}
public void setAdresse(HashSet<adresse> adresse) {
this.adresse = adresse;
}
}
Class adresse
package de.testpackage;
import javax.persistence.*;
@Entity
public class adresse {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
String Adresse;
public adresse() {
}
public String getAdresse() {
return Adresse;
}
public void setAdresse(String adresse) {
Adresse = adresse;
}
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}
的persistence.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<class>de.testpackage.people</class>
<class>de.testpackage.adresse</class>
<class>de.testpackage.register</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpatest2" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="root" />
<!-- Optimize database writes using batching -->
<property name="eclipselink.jdbc.batch-writing" value="JDBC" />
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
我希望有人可以帮我解决这个问题。
BR 拉尔夫
答案 0 :(得分:1)
问题在于你如何使用em.merge(r)。 Merge接受您传入的分离实体,并将该状态合并到它管理的实例/副本中。管理副本在事务提交时分配了其ID - 无论如何都未触及或更改您的“r”实例。您需要在事务提交后传回托管实例。对于显示的代码,只需将em.merge(r)
更改为
r = em.merge(r);
为您提供在事务提交时获取其ID的引用实体的句柄。