-->
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.  [ 9 posts ] 
Author Message
 Post subject: Non-cascaded delete not working as expected.
PostPosted: Mon Aug 29, 2005 9:58 am 
Newbie

Joined: Mon Aug 29, 2005 9:41 am
Posts: 6
Location: Leicester, England
Hibernate version: 3.0.5 Annotations V 3.0 beta 2

Mapping documents:
SalesPerson.java
Code:
@Entity
public class SalesPerson {
   
   public String getEmail() {
      return email;
   }

   @Id( generate=GeneratorType.AUTO )
   public Long getId() {
      return id;
   }

         public String getName() {
      return name;
   }

   @OneToMany(
         cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH},
         fetch=FetchType.EAGER,
         mappedBy="responsible"
   )
   public Set<Market> getResponsibleMarkets() {
      return responsibleMarkets;
   }

   @Version
   public Integer getVersion() {
      return version;
   }
}


Market.java
Code:
@Entity
public class Market {
   @Id( generate=GeneratorType.AUTO )
   public Long getId() {
      return id;
   }

   public String getName() {
      return name;
   }

   @ManyToOne(
         cascade={CascadeType.ALL}
   )
   public SalesPerson getResponsible() {
      return responsible;
   }

   @Version
   public Integer getVersion() {
      return version;
   }
}


Name and version of the database you are using: MySQL 4.1.13a Connector version 3.1.10
Using MySQLInnoDBDialect

When I delete a SalesPerson that is associated to a Market I expect that the reference within the Market instance be set to null(Note I have not set CascadeType.DELETE) as a Market should still be allowed to exist. However I'm receiving a ConstraintViolationException.

Do I need to manually nullify this reference?

If so what is the most efficient method of doing this?

If not, what have I got wrong in the configuration?

Or is this a bug?

Thanks in advance for your help.

Jon


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 11:32 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
You have to nullify the other side, exacly as if you were working on a Java only environment. In a plain object model, you remove the object from the collection and nullify the association on the other side.

The faste I can see is market.setResponsible(null);

The convinient way is to create some helper method on sales representative.

addMarket()
removeMarket() that does the nullify and the collection removal job.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 12:50 pm 
Newbie

Joined: Mon Aug 29, 2005 9:41 am
Posts: 6
Location: Leicester, England
Ok...before I saw your response, I managed to get the effect I wanted by using the following in my SalesPersonDao

Code:
public void removeSalesperson(SalesPerson person) {
   Set<Market> markets = person.getResponsibleMarkets();
   for (Market market : markets) {
      market.setResponsible( null );
      getHibernateTemplate().saveOrUpdate( market );
   }
   getHibernateTemplate().delete( person );
}

(Yes, I'm using Spring too but that shouldn't be a factor in this)

Now my new question is why doesn't the following work...
Code:
public void removeSalesperson(SalesPerson person) {
   Set<Market> markets = person.getResponsibleMarkets();
   for (Market market : markets) {
      market.setResponsible( null );
   }
   getHibernateTemplate().saveOrUpdate( person );
   getHibernateTemplate().delete( person );
}

Surely the saveOrUpdate should cascade the changes to the Market objects before I then call delete, but this doesn't happen, I again have problems with integrity constraints. At the end of the day this isn't too big a deal for me at the mo but surely the loop should be moved into a helper method within the SalesPerson class, but this is not possible as the domain object shouldn't have to know about hibernate... Ideally I would like to be able to re-write my DAO so that it becomes...
Code:
public void removeSalesperson(SalesPerson person) {
   person.removeResponsibilities();
   getHibernateTemplate().saveOrUpdate( person );
   getHibernateTemplate().delete( person );
}

Any thoughts on how this could be achieved?

Thanks

Jon


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 30, 2005 1:33 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
try to flush before delete

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 31, 2005 7:36 am 
Newbie

Joined: Mon Aug 29, 2005 9:41 am
Posts: 6
Location: Leicester, England
Thanks for your response, I changed my code to....
Code:
public void removeSalesperson(SalesPerson person) {
   Set<Market> markets = person.getResponsibleMarkets();
   for (Market market : markets) {
      market.setResponsible( null );
   }
   markets.clear();
   getHibernateTemplate().saveOrUpdate( person );
   getHibernateTemplate().flush();
   getHibernateTemplate().delete( person );
}

I tried it with and without the markets.clear() line, but I still get the same ConstraintViolationException :-(

Any other ideas?

Jon


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2005 7:06 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
you update market by nullifying the relation but you don't reattach market to your session. So this update is not seen by hibernate

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 02, 2005 9:22 am 
Newbie

Joined: Mon Aug 29, 2005 9:41 am
Posts: 6
Location: Leicester, England
Ok, I understand that, but if I am to avoid an Anaemic Domain Model I should be moving the loop into a method such as "removeResponsibilities" in here I would not have (and should not have) any reference to the persistence framework, so how should I go about re-attaching the Markets? Surely this is a not a new problem, people have surely manipulated one to many links before in this manner, what is the recommended practice (other than an Anaemic Domain Model)?

Thanks

Jon


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 02, 2005 10:44 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
attach them before your loop either explicitly or through a cascade strategy

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 02, 2005 12:01 pm 
Newbie

Joined: Mon Aug 29, 2005 9:41 am
Posts: 6
Location: Leicester, England
How do I do this? Due to my annotations every action other than a delete should be cascaded so I have tried the following before my loop;

Code:
getHibernateTemplate().refresh( person )

This one gives me a StackOverflowError, infinite loop maybe?...
Quote:
java.lang.StackOverflowError
at java.util.HashMap.hash(Unknown Source)
at java.util.HashMap.get(Unknown Source)
at org.hibernate.impl.SessionFactoryImpl.getCollectionPersister(SessionFactoryImpl.java:575)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:786)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
at org.hibernate.engine.Cascades.cascade(Cascades.java:819)
at org.hibernate.event.def.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:85)
at org.hibernate.impl.SessionImpl.refresh(SessionImpl.java:679)
at org.hibernate.engine.Cascades$3.cascade(Cascades.java:112)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:771)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
at org.hibernate.engine.Cascades.cascade(Cascades.java:819)
... goes on a few more times


Code:
getHibernateTemplate().merge( person )

This one gets really confusing...
Quote:
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [model.SalesPerson#112]; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [model.SalesPerson#112]
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.opera.interview.model.SalesPerson#112]
at org.hibernate.persister.entity.BasicEntityPersister.check(BasicEntityPersister.java:1441)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:1986)
at org.hibernate.persister.entity.BasicEntityPersister.updateOrInsert(BasicEntityPersister.java:1909)
at org.hibernate.persister.entity.BasicEntityPersister.update(BasicEntityPersister.java:2149)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:75)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:137)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:730)
at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:394)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:316)
at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:627)
at persistence.SalesPersonDaoHibernate.removeSalesperson(SalesPersonDaoHibernate.java:58)


Code:
getHibernateTemplate().persist( person )

This one really has me stumped as I have an assertNotNull( person ) in my test case just before calling this method...
Quote:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: null; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: null
org.hibernate.PersistentObjectException: detached entity passed to persist: null
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:79)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:38)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:525)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:529)
at org.springframework.orm.hibernate3.HibernateTemplate$21.doInHibernate(HibernateTemplate.java:662)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:315)
at org.springframework.orm.hibernate3.HibernateTemplate.persist(HibernateTemplate.java:659)
at persistence.SalesPersonDaoHibernate.removeSalespersonWorking(SalesPersonDaoHibernate.java:46)


Code:
getHibernateTemplate().saveOrUpdate( person )

This gives the original ConstraintViolationException :-(

I'm obviously doing something seriously wrong here...any further ideas?

Thanks for your help so far.

Jon


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 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.