hibernate - Java JPA Unit Test saving 2 items -
i have simple @onetomany
setup 2 entities - item
, group
, , having interesting problem. when integration test creates group
, adds item
, saves group
, 2 instances of item
end getting saved. ideas why? i'm using hibernate, if matters:
the item entity
@entity public class namedentity implements java.io.serializable { long id; @notnull string name; namedentitygroup namedentitygroup; namedentitytype type; @enumerated(enumtype.string) public namedentitytype gettype() { return type; } @id @generatedvalue public long getid() { return id; } public string getname() { return name; } @joincolumn(name = "namedentitygroupid") @jsonbackreference @manytoone(cascade = { cascadetype.all }, fetch = fetchtype.eager) public namedentitygroup getnamedentitygroup() { return this.namedentitygroup; } }
the group entity
@entity public class namedentitygroup implements serializable { long id; string name; list<namedentity> namedentities; @id @generatedvalue public long getid() { return this.id; } public string getname() { return this.name; } @jsonmanagedreference @onetomany(cascade = { cascadetype.all }, mappedby = "namedentitygroup", fetch = fetchtype.eager) public list<namedentity> getnamedentities() { return this.namedentities; } public void addnamedentity(namedentity ne) { if (this.namedentities == null) { this.namedentities = new arraylist<namedentity>(); } if (!namedentities.contains(ne)) { this.namedentities.add(ne); } ne.setneg(this); } }
the dao class
public void save(namedentity ne) throws entityvalidationexception { validate(ne); if(ne.getnamedentitygroup() != null) { if(!em.contains(ne.getnamedentitygroup())) { ne.setnamedentitygroup(em.merge(ne.getnamedentitygroup())); em.persist(ne); return; } } em.persist(ne); }
the test method
@test public void testaddnamedentitytoexistinggroup() throws entityvalidationexception { int nesize = ed.getallnamedentities().size(); namedentitygroup neg = ed.getallnamedentitygroups().iterator().next(); assertnotnull(neg); asserttrue(neg.getnamedentities().size() == 0); em.detach(neg); namedentity n = new namedentity(); n.setname("hello"); neg.addnamedentity(n); n.setnamedentitygroup(neg); n.settype(namedentitytype.default); ed.save(n); for(namedentity e : ed.getallnamedentities()) { l.error("entity: {}", e); } asserttrue("size " + ed.getallnamedentities().size() + " should " + (nesize + 1) + " group has " + neg.getnamedentities().size() + " entities (should 1) " + ed.getallnamedentities(), nesize + 1 == ed.getallnamedentities().size()); }
here output:
entity: namedentity [id=1, name=super mario brothers, namedentitygroup=null, type=null] entity: namedentity [id=3, name=mario kart, namedentitygroup=null, type=null] entity: namedentity [id=5, name=f-zero, namedentitygroup=null, type=null] entity: namedentity [id=7, name=hello, namedentitygroup=namedentitygroup [id=2, name=super mario brothers, count(entity)=1], type=default] entity: namedentity [id=8, name=hello, namedentitygroup=namedentitygroup [id=2, name=super mario brothers, count(entity)=1], type=default]
id's 7
, 8
duplicates in output save
method inserting item 2 times.
your dao save
method ugly, refactor it, otherwise expect more issues one. :)
the issue in em.merge(ne.getnamedentitygroup())
in dao save
method. because namedentitygroup
cascades all
namedentities
, merge
cascaded ne
transient (unsaved), causing new namedentity
instance created. ne
instance removed namedentities
collection , copy of placed in it. session.merge javadoc:
copy state of given object onto persistent object same identifier. if there no persistent instance associated session, loaded. return persistent instance. if given instance unsaved, save copy of , return newly persistent instance. given instance not become associated session. operation cascades associated instances if association mapped cascade="merge".
afterwards persist passed in ne
well, end 2 persisted namedentity
instances: 1 created (copied) merge
, 1 explicitly persisted (ne
).
the proper solution refactor save
not contain code if(!em.contains(ne.getnamedentitygroup()))
, similar things.
the ugly quick fix remove unnecessary em.persist(ne)
if
body. make things work, confusing (the passed in ne
still transient after save
returns).
a little better quick fix load persistent namedentitygroup
:
namedentitygroup group = em.getreference(namedentitygroup.class, ne.getnamedentitygroup().getid()); ne.setnamedentitygroup(group);
Comments
Post a Comment