jsf - JPA update one to one association object leads to duplicate entry exception -
i using jsf 2.0, tomcat 7.x , eclipselink jpa-provider. want update entity instance onetoone association, more precisely booking got user property named booker. unfortunately if invoke updatebooking() api-method, eclipselink want create new booker instead of using exisiting user. eclipse console stacktrace , relevant code snippets added - in advance hints!
stacktrace:
caused by: exception [eclipselink-4002] (eclipse persistence services - 2.3.1.v20111018-r10243): org.eclipse.persistence.exceptions.databaseexception internal exception: com.mysql.jdbc.exceptions.jdbc4.mysqlintegrityconstraintviolationexception: duplicate entry '1' key 'email' error code: 1062 call: insert user (email, name, password) values (?, ?, ?) bind => [3 parameters bound] query: writeobjectquery(logstring user - id: 1; name: 1; email: 1;) @ org.eclipse.persistence.exceptions.databaseexception.sqlexception(databaseexception.java:324) @ org.eclipse.persistence.internal.databaseaccess.databaseaccessor.executedirectnoselect(databaseaccessor.java:840) ... caused by: com.mysql.jdbc.exceptions.jdbc4.mysqlintegrityconstraintviolationexception: duplicate entry '1' key 'email' @ sun.reflect.nativeconstructoraccessorimpl.newinstance0(native method) @ sun.reflect.nativeconstructoraccessorimpl.newinstance(unknown source)
developmentcontroller.java
public string testupdatebooking(){ string str = "/development.xhtml?faces-redirect=true"; try { integer bookingid = 22; integer bookerid = 1; bookerapi api = new bookerapi(); booking booking = api.readbooking(bookingid); user booker = api.readuser(bookerid); booking.setbooker(booker); api.updatebooking(booking); message = "developmentcontroller.testupdatebooking() " + booking; } catch (runtimeexception exc){ message = "exception developmentcontroller.testupdatebooking();"; exc.printstacktrace(); } return str; }
bookerapi.java
public void updatebooking(booking booking){ emf = persistence.createentitymanagerfactory(persistence_unit_name); entitymanager em = emf.createentitymanager(); em.gettransaction().begin(); booking persbooking = em.find(booking.class, booking.getid()); persbooking.setcourtno(booking.getcourtno()); persbooking.setstart(booking.getstart()); persbooking.setend(booking.getend()); persbooking.setbooker(booking.getbooker()); em.gettransaction().commit(); // haendelt update implizit, kracht em.clear(); emf.close(); }
entity booker properties:
@id @generatedvalue(strategy = generationtype.identity) integer id; @temporal(temporaltype.date) @column(nullable = false) date start; @temporal(temporaltype.date) @column(nullable = false) date end; @column(nullable = false) integer courtno; @onetoone(fetch = fetchtype.eager) // mueller s. 105, 109 @joincolumn(name = "user") user booker;
entity user properties:
@id @generatedvalue(strategy = generationtype.identity) private integer id; @column(unique = true, nullable = false) private string name; @column(nullable = false) private string password; // todo verschluesseln @column(unique = true, nullable = false) private string email;
many things :
1 : fix
don't need write crud method in jpa, entitymanager provides required ones
public void updatebooking(booking booking){ emf = persistence.createentitymanagerfactory(persistence_unit_name); entitymanager em = emf.createentitymanager(); em.gettransaction().begin(); em.merge(booking); em.gettransaction().commit(); em.close(); emf.close();
but
you shouldn't handle transaction way, transaction should opened in service layer not in data access one. in fact, should managed container if have 1 (means using spring or java ee server) using @transactional annotation. if absolutely want manage manually, must handle eventual exception , rollback in case meet one. entitymanager , underlying transaction have same scope/lifecycle.
moreover should have 1 entitymanagerfactory app.
otherwise don't need specify fetch type here, onetoone association eagerly fetched.
Comments
Post a Comment