JPA throws no EntityExistsException but generates a duplicate row (auto generated PK)

喜欢而已 提交于 2019-12-25 07:29:13

问题


I am new to JPA and was experimenting a bit in hope of figuring out the Entity lifecycle model. I expected the code below to throw an EntityExistsException. However, instead of throwing the expected exception, it just creates a new row in database table with a new primary key (incremented by one).

Can anyone explain this? I suspect it might have something to do with the @GeneratedValue annotation on my ID field in combination with my autoincrementing primary key in the corresponding table.

Below you can find 3 snippets: the code I try to run, my entity definition and my table design.

I would like to thank you in advance for shining your light on my misunderstanding.

Kind regards

ps: I use eclipselink as jpa implementation and a Derby database

Script:

    Teacher teacher = new Teacher("John","Doe","English");

    //Persist John Doe
    EntityManager em = Persistence.createEntityManagerFactory("jpatest").createEntityManager(); 
    em.getTransaction().begin();
    em.persist(teacher);
    em.getTransaction().commit();
    em.close();

    //Try to persist John Doe a second time
    em = Persistence.createEntityManagerFactory("jpatest").createEntityManager();
    em.getTransaction().begin();
    em.persist(teacher);
    em.getTransaction().commit(); //I Expect a throw here
    em.close();

Table Design:

CREATE TABLE teachers (id INT GENERATED ALWAYS AS IDENTITY, firstname VARCHAR(20) ,lastname VARCHAR(40), PRIMARY KEY(id))

Entity definition:

package testpackage;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name="teachers", schema="USERNAME")
public class Teacher {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String firstName;

    private String lastName;

    @Transient
    private String course;




    /**
     * Zero argument constructor for JPA
     */
    Teacher(){
    }

    public Teacher(String firstName, String lastName, String course){
        this.firstName = firstName;
        this.lastName = lastName;
        this.course = course;
    }




    public int getId(){
        return id;
    }
    public String getFirstName(){
        return firstName;
    }
    public String getLastname(){
        return lastName;
    }
    public String getCourse(){
        return course;
    }



    public void setFirstName(String firstName){
        this.firstName = firstName;
    }
    public void setLastName(String lastName){
        this.lastName = lastName;
    }
}

回答1:


EntityExistsException will be thrown only when you are persisting the same entity associated with DB.

but here you have created one Object with some values and then persisting 2 times with primary key generated automatically unique for each persistence.

because

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

will generate new ID each time you call persist method with Entity manager. and henc eboth the entities becomes different with respect to DB is concerned. because DB cares for primary key to be unque to distinguish each record.

so better you do this to get that exception

get the entity from DB first and change it and try to call save on it

EntityManager em = Persistence.createEntityManagerFactory("jpatest").createEntityManager(); 
    em.getTransaction().begin();
Teacher teacher = em.find(Teacher.class,primary key)
    em.persist(teacher);
    em.getTransaction().commit();
    em.close();

or else remove autogeneration of primary key and assign it manually same id both the time. let me know for any other questions




回答2:


It is clear form exception the entity already exists, if already exists the EntityExistsException may be thrown when the persist operation is invoked.

EclipseLink does not include the Id in the INSERT for Derby IDENTITY, so you have something odd going on.

Did you previously use another generator strategy and not recompile/deploy your code correctly?

Also try setting your platform using the"eclipselink.target-database"="Derby" in your persistence.xml.

make little change

id INT GENERATED ALWAYS AS IDENTITY

use START WITH 1, INCREMENT BY 1 for PK.

id INT GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)


来源:https://stackoverflow.com/questions/23217972/jpa-throws-no-entityexistsexception-but-generates-a-duplicate-row-auto-generate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!