-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Fri Feb 08, 2008 11:00 am 
Pro
Pro

Joined: Tue Jun 12, 2007 4:13 am
Posts: 209
Location: Berlin, Germany
Hi,

I have an entity in the role of an owner on a set of dependent entities; the owner's set is mapped with
Code:
cascade = {CascadeType.ALL}
, and, because the dependent entities are not used elsewhere, it is also mapped with
Code:
org.hibernate.annotations.CascadeType.DELETE_ORPHAN.


So, my understanding is: if I remove an entity from the collection and then call EntityManager.merge on the parent (the whole object graph is detached!) , Hibernate should detect that the collection has changed, and it should automatically delete the now orphaned entity. That is: without explicitly removing the entity by my program code.

Now I have 2 different constructs like that, where in one scenario this works as I expected, but not in the other.

In the case where this automatic deletion works as expected, the collection is mapped as a List and with a JoinColumn. Whereas in the other case the collection is mapped as a Set and with a JoinTable. In my humble opinion this should make no different behaviour - but it seems it does!

Please note that I use the returned object from EntityManager.merge(); I can clearly see, that the deleted object is not contained anymore in the set.

Has anyone an explanation? Or can you tell me what is the best way to handle a case like this? As I'm using detached objects my expectation is to just always call EntityManager's merge method to do updates.

Carlo


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 08, 2008 12:50 pm 
Newbie

Joined: Fri Feb 08, 2008 12:23 pm
Posts: 2
I think the problem is u are using a join table. Join tables aren't used for dependant entities but for many-to-many associations. What hibernate does is delete the association in the join table but it does not delete the child entity. I think this is intended behavior, because it assumes the orphan entity can be referenced by another join table record. If u want it to be as expected, don't use join tables but have the childs reference directly to their parent. (one-to-many,many-to-one)


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Fri Feb 08, 2008 12:55 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
What is the mapping for the one that doesn't work?


Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 09, 2008 9:48 am 
Pro
Pro

Joined: Tue Jun 12, 2007 4:13 am
Posts: 209
Location: Berlin, Germany
Kayseryu wrote:
What hibernate does is delete the association in the join table but it does not delete the child entity.


No, this not the case. It doesn't delete the join table entry nor the entity itself - Hibernate does just do nothing! And that's my problem.

Carlo


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Thu Feb 14, 2008 3:57 am 
Pro
Pro

Joined: Tue Jun 12, 2007 4:13 am
Posts: 209
Location: Berlin, Germany
farzad wrote:
What is the mapping for the one that doesn't work?


OK, here it is (sorry for that late response, I was lying ill in bed last days)

first, this is the mapping which does not work as I expect it:

(a Contact may be the owning parent of several BankAccount objects:
Code:
class BankAccount {
....

@ManyToOne
@JoinColumn(name = "CONTACT_ID", nullable=false, updatable=false, insertable=false) // Hibernate book, p. 294!!   @org.hibernate.annotations.ForeignKey(name="FK_CONTACT_BANKACCNT_ID")
private Contact contact;

class Contact {
...

@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
   @JoinColumn(name = "CONTACT_ID", nullable = false)
   @org.hibernate.annotations.IndexColumn(name="BANK_LISTPOS")
   @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private List<BankAccount> bankAccounts = new ArrayList<BankAccount>();


And here is the relation, where DELETE_ORPHAN does what i expected it to do:

(an Institution may have several PersonContacts )

Code:
class PersonContact {
...
@ManyToOne(optional = true)  //, cascade=CascadeType.ALL)
   @JoinTable(name = "PERSON_INST_CONTACT",
             joinColumns = { @JoinColumn(name = "PERSON_ID") },
             inverseJoinColumns = { @JoinColumn(name = "CONTACT_ID") })
  @org.hibernate.annotations.ForeignKey(name="FK_PERSON_INSTITUT_ID")       
   private InstitutionContact institution;

class InstitutionContact {
...
@OneToMany(mappedBy="institution",
             cascade = {CascadeType.MERGE,CascadeType.REMOVE}, // cascade = {CascadeType.ALL},http://www.junlu.com/msg/390434.html
             fetch = FetchType.EAGER)
  // we can savely let Hibernate do a cascade orphan delete:
  @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<PersonContact> persons = new HashSet<PersonContact>();


To repeat my situation: Firstly, I work with detached objects. A Java desktop client (actually a EJB client) requests the business objects from server (entities) and acts on them (may create new ones, delete others). That is, the set of PersonContacts is displayed in a JTable, and the user may delete a row from this table. The same applies to the BankAccounts. So, when the user presses OK (=save), the object graph is passed back to the EJB server, where an EntityManager just calls merge() on the root object. The rest is expected to be done by Hibernate.

To repeat: automatic detection of the deletion of a BankAccount works as expected: Hibernate generates the SQL for it; but this is not the case for the PersonContact.

I cannot see why Hibernate acts differently on the slightly different associations. Maybe it is the @JoinTable I use on that association (I have some reasons for it).

So, do you have an idea what to do? I don't think that it should be the task of my EJB to track changes on the persistent objects themself. If it was, why should I use an ORM at all -:) ?

Carlo


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Thu Feb 14, 2008 8:41 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
Add PERSIST cascade to cascade = {CascadeType.MERGE,CascadeType.REMOVE} and you are good. The problem here is that hibernate does not cascade delete orphans at the merge time so it has no effect, and at the flush time it checks if it should cascade persist to the collection and the answer is no.



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 14, 2008 9:35 pm 
Beginner
Beginner

Joined: Thu Dec 13, 2007 2:32 pm
Posts: 26
Is it true ? can you link me to the reference where it says that during merge, delete on orphan isnt valid ... ?

my question is if i have cascade ="save-update,delete-orphan" and i just use merge, will it work ?

_________________
Regards,
Vyas, Anirudh


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Fri Feb 15, 2008 3:30 am 
Pro
Pro

Joined: Tue Jun 12, 2007 4:13 am
Posts: 209
Location: Berlin, Germany
farzad wrote:
Add PERSIST cascade to cascade = {CascadeType.MERGE,CascadeType.REMOVE} and you are good.


Hi Farzad,

yes, now I'm good - it works as expected! Of course adding the PERSIST option to MERGE and REMOVE adds noise; so I just did it with
Code:
cascade = {CascadeType.ALL}
and (as I strongly hoped) this also works.

Thanks

Carlo


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 16, 2008 1:43 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
anirudhvyas010 wrote:
Is it true ? can you link me to the reference where it says that during merge, delete on orphan isnt valid ... ?

my question is if i have cascade ="save-update,delete-orphan" and i just use merge, will it work ?



You do need persist in the list. save-update, delete-orphan are not enough.



Farzad-


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Thu Apr 08, 2010 4:07 pm 
Newbie

Joined: Thu Apr 08, 2010 1:27 pm
Posts: 1
I am having a similar problem as the original author of this threat. I am creating managed children and adding/removing them from a parent list before calling flush on the EntityManager similar to the pseudo-code below:

Code:
Parent parent = // load parent from context;
parent.setSomeProperty(toSomeNewValue);

Child child = new Child();
entityManager.manage(child);  // or entityManager.persist(child), either behaves the same
parent.getChildren().add(child);
parent.getChildren().clear(); // with DELETE_ORPHAN cascade type, shouldnt this also prevent 'child'
                                       // from becoming an orphan as well as removing orphans that are already committed?
entityManager.flush();


In the above code, parent and child are lifecycle linked.

The desired behavior is for the .clear() to remove all children both from the database and from the context (if the child has not yet been committed to the database like in this example). Instead, the parent is being updated in the DB, the child is being inserted into the DB and no link is being persisted in the join table between them. The undesired behavior is that the child is being persisted even though it was (for a short period) added to the parent's list of children and then later removed before the flush. The problem is more complicated when I start to give the child its own children. Each of those children are also inserted, and so I have an orphaned tree of objects, not just the top-level child under Parent.

Here are how my annotations are set up on Parent and Child:

Code:
@Entity
class Parent {
  private List<Child> children;
  public void setChildren(List<Child> children) { this.children = children; }

  @OneToMany(cascade = CascadeType.ALL)
  @Cascade( { org.hibernate.annotations.CascadeType.ALL,
                     org.hibernate.annotations.CascadeType.DELETE_ORPHAN })   
  /* Note: default mapping uses join table */
  public List<Child> getChildren() { return children; }
}

@Entity
class Child {
  // nothing here.  I dont want the child to know about the parent, so this relationship is uni-directional
}


My question is, does the PersistentBag/List implementation track non-committed managed entities when they are added and then when they are removed, does it or is it supposed to remove those entities from the context so that they are not committed (inadvertently generating orphans?).

Looking at PersistentBag.java, I noticed that the implementation of the void remove(Object o) method for the List interface does not do any bookkeeping of what un-committed children were added and then later removed. That implies that the detection of orphans happens at flush-time. This creates inconsistent behavior at the interface level for programmers that expect remove with delete-orphans to remove not only committed children that were removed from the list, but also un-committed children that were added to the list and then removed before the entity manager is flushed. Right? Is there a best-practice to do what I want to do in a somewhat generic manner?

Keith


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Thu May 19, 2011 7:58 am 
Newbie

Joined: Thu May 19, 2011 7:54 am
Posts: 1
I have the same problem.

If I remove an element from this collection
Code:
    @OneToMany(fetch = FetchType.EAGER, cascade = { javax.persistence.CascadeType.ALL })
    @JoinColumn(name = "commercial_offer_id")
    @Cascade( { CascadeType.DELETE_ORPHAN })
    private Set<CommercialOfferCountryDraft> commercialOfferCountry;


on database the field commercial_offer_id became NULL but no DELETE is executed

someone can help me?


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Fri Jun 24, 2011 12:25 pm 
Newbie

Joined: Fri Jun 24, 2011 12:22 pm
Posts: 2
Hi All,

I ran in to the same issue. When I try to delete one object from the child objects collection, In the database specific row values are becoming null except composite primary key. But it is not getting deleted.
Please let me know If you find the solution for this problem

Thanks


Top
 Profile  
 
 Post subject: Re: Deleting an entity from a collection: DELETE_ORPHAN?
PostPosted: Fri Jun 24, 2011 12:57 pm 
Newbie

Joined: Fri Jun 24, 2011 12:22 pm
Posts: 2
wow!!! I got the solution.
In the persist method, I am doing following stuff.

log.info("persisting Partner instance");
Session session = null;
try {
session = getSession();
List<PpPartnerVendorBkgTrx> vendors = transientInstance
.getPpPartnerVendorBkgTrxes();
if (vendors != null && vendors.size() > 0) {
Iterator<PpPartnerVendorBkgTrx> it = vendors.iterator();
while (it.hasNext()) {
PpPartnerVendorBkgTrx v = it.next();
if (v != null) {

if (v.getPpVendor() == null) {
it.remove();
session.delete(v);
} else {
if (v.getId() != null && v.getPpVendor() != null)
v.getId().setVendorId(
v.getPpVendor().getVendorId());
}
}

}
}

session.saveOrUpdate(transientInstance);
session.flush();
log.info("persist successful");
return (Long) session.getIdentifier(transientInstance);
} catch (RuntimeException re) {
log.error("persist failed", re);
re.printStackTrace();
throw re;
} finally {
TransactionSynchronizationManager.unbindResource(hibernateTemplate
.getSessionFactory());
SessionFactoryUtils.releaseSession(session,
hibernateTemplate.getSessionFactory());
}


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.