使用一对多通过非更新ID(PrimaryKey)的重复条目

时间:2013-12-03 17:46:08

标签: eclipselink one-to-many persist

我有一个我无法理解的问题,也没有找到任何真正的解决方案。我有一个对象模型,其中一个类中有一堆集合,这些集合的对象中还有其他实体。所有这些集合都将使用一对多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 拉尔夫

1 个答案:

答案 0 :(得分:1)

问题在于你如何使用em.merge(r)。 Merge接受您传入的分离实体,并将该状态合并到它管理的实例/副本中。管理副本在事务提交时分配了其ID - 无论如何都未触及或更改您的“r”实例。您需要在事务提交后传回托管实例。对于显示的代码,只需将em.merge(r)更改为

即可
  r = em.merge(r);

为您提供在事务提交时获取其ID的引用实体的句柄。