java - JPA handle merge() of relationship -
i have unidirectional relation project -> projecttype
:
@entity public class project extends namedentity { @manytoone(optional = false) @joincolumn(name = "type_id") private projecttype type; } @entity public class projecttype extends lookup { @min(0) private int progressive = 1; }
note there's no cascade.
now, when insert new project need increment type progressive.
this i'm doing inside ejb, i'm not sure it's best approach:
public void create(project project) { em.persist(project); /* necessary merge type? */ projecttype type = em.merge(project.gettype()); /* necessary set type again? */ project.settype(type); int progressive = type.getprogressive(); type.setprogressive(progressive + 1); project.setcode(type.getprefix() + progressive); }
i'm using eclipselink 2.6.0, i'd know if there's implementation independent best practice and/or if there behavioral differences between persistence providers, specific scenario.
update
to clarify context when entering ejb create method (it invoked jsf @managedbean
):
project.projecttype
detachedproject
new- no transaction (i'm using jta/cmt) active
i not asking difference between persist()
, merge()
, i'm asking if either
- if
em.persist(project)
automatically "reattach"project.projecttype
(i suppose not) - if legal call order: first
em.persist(project)
em.merge(projecttype)
or if should inverted - since
em.merge(projecttype)
returns different instance, if required callproject.settype(managedprojecttype)
an explaination of "why" works in way , not in welcome.
you need merge(...)
make transient entity managed entity manager. depending on implementation of jpa (not sure eclipselink) returned instance of merge
call might different copy of original object.
myentity unmanaged = new myentity(); myentity managed = entitymanager.merge(unmanaged); assert(entitymanager.contains(managed)); // true if worked out assert(managed != unmanaged); // true, depending on jpa impl.
if call manage(entity)
entity
managed, nothing happen.
calling persist(entity)
make entity managed, returns no copy. instead merges original object , might call id generator (e.g. sequence), not case when using merge
.
see this answer more details on difference between persist
, merge
.
here's proposal:
public void create(project project) { projecttype type = project.gettype(); // maybe check if null if (!entitymanager.contains(type)) { // type transient type = entitymanager.merge(type); // or load type project.settype(type); // update reference } int progressive = type.getprogressive(); type.setprogressive(progressive + 1); // mark dirty, update on flush // set "code" before persisting "project" ... project.setcode(type.getprefix() + progressive); entitymanager.persist(project); // ... no additional update required after // insert on "project". }
update
if em.persist(project) automatically "reattach" project.projecttype (i suppose not)
no. you'll exception (hibernate anyway) stating, you're trying merge transient reference.
correction: tested hibernate , got no exception. project created unmanaged project type (which managed , detached before persisting project). but project type's progression
not incremented, expected, since wasn't managed. yeah, manage before persisting project.
if legal call order: first em.persist(project) em.merge(projecttype) or if should inverted
it's best practise so. when both statements executed within same batch (before entity manager gets flushed) may work (merging type after persisting project). in test worked anyway. said, it's better merge entities before persisting new ones.
since em.merge(projecttype) returns different instance, if required call project.settype(managedprojecttype)
yes. see example above. persistence provider may return same reference, isn't required to. sure, call project.settype(mergedtype)
.
Comments
Post a Comment