jpa - Issue with bidirectional one-to-one relationship trying to INSERT instead of UPDATE in Java EclipseLink -


i'm having trouble understanding why bidirectional relationship not working here quite expect to. when persist owning side after setting relationships both ways, cascading takes place , 'insert inverseside' sql statement executed. causes exception thrown trying add duplicate pk inverse side entity's table.

i'd assume there should 'update' statement instead, inverse side entity in db , - far rookie guts can tell - managed jpa.

database mockup:

table inverseside   id  table owningside   id   inverseside_id 

java mockup:

dao interfaces

@repository public interface isdao extends jparepository<inverseside, long>  @repository public interface osdao extends jparepository<owningside, long> 

entity classes

public class inverseside {   private long id;    @onetoone(optional = true, mappedby = "inverse")   private owningside owner;    public void setowner(owningside os) {     owner = os;   } }  public class owningside {   private long id;    @onetoone(optional = false, cascade = cascadetype.all)   private inverseside inverse;    public void setinverse(inverseside is) {     inverse = is;     inverse.setowner(this);   } } 

test code

inverseside inverse = isdao.findall().get(0); // returns valid object id 1000 owningside owner = new owningside();  owner.setinverse(inverse); osdao.save(owner); // exception  /*   org.springframework.transaction.transactionsystemexception:    not commit jpa transaction; nested exception    javax.persistence.rollbackexception: exception [eclipselink-4002] (eclipse    persistence services - 2.7.0.v20170811-d680af5):    org.eclipse.persistence.exceptions.databaseexception   internal exception: org.h2.jdbc.jdbcsqlexception: unique index or primary    key violation: "primary key on public.inverseside(id)"; sql statement:   insert inverseside (id, ...   error code: 23505   call: insert inverseside (id, ...           bind => [1000, ... */ 

update

inverse side insert due owning side being new - , consequently unmanaged - jpa. in other words, though known jpa's point of view, persisting unmanaged os led connected being treated unmanaged.

thus, answer persist new inverseless owner first, complete relationship both ways , persist owner again:

inverseside inverse = isdao.findall().get(0); owningside owner = new owningside();  osdao.save(owner);  owner.setinverse(inverse); osdao.save(owner); 

perhaps should have anticipated behavior. however, doesn't feel intuitive, , none of sources studied mentioned this.

most instances of type of problem comes due fact object inverse detached. barring specific transactional boundaries, each call repository methods own transaction, , return value detached. , thinks it's new object, , insert instead of update.

however, if have transactional boundaries set properly, don't think jpa implementation want do. it's not simple matter of updating is. you're expectations, in pseudo code:

select os os.is.id = :isid  update os set = null os.is.id = :isid  insert os (:newos) 

the first 2 statements isn't in realm of responsibility entity manager. implementation seems more appropriate manytoone relationship. otherwise, should load other os, remove it's attachment is, save that, create new os, attach is, , save that. in same transaction.


Comments

Popular posts from this blog

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

python Tkinter Capturing keyboard events save as one single string -

sql server - Why does Linq-to-SQL add unnecessary COUNT()? -