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
Post a Comment