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.  [ 4 posts ] 
Author Message
 Post subject: cascade=all, hibernate update works except with orphans
PostPosted: Fri Apr 21, 2006 9:06 pm 
Regular
Regular

Joined: Thu Sep 16, 2004 4:56 pm
Posts: 80
Sorry, I kept trying. I know this has to be a simple mistake somewhere. I have a hibernate bean with the following methods.....

@Column(name="iteration_id")
@OneToMany(mappedBy="iteration", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
public Collection<RequirementDBO> getRequirements() {
if(requirements == null) {
requirements = new ArrayList<RequirementDBO>();
}
return requirements;
}

public void setRequirements(Collection<RequirementDBO> requirements) {
this.requirements = requirements;
}

public void addRequirement(RequirementDBO req) {
getRequirements().add(req);
req.setIteration(this);
}

public void removeRequirement(RequirementDBO req) {
if(requirements == null || !requirements.contains(req))
throw new IllegalArgumentException("This iteration does not contain this requirement");
requirements.remove(req);
req.setIteration(null);
}

I am using a transaction and when I add RequirementDBO's to the collection above, it updates the database correctly. When I remove RequirementDBO's from the collection, the database is not updated. The Requirement in the table still is associated with the iteration. I am using the same code for the transaction on the add and remove with the mgr.merge(iteration) call. Here is the main code.....

IterationDBO iteration = DatabaseFacade.getInstance().getIteration(release, iterationNum);
if(iteration == null) {
log.info("CREATING iteration");
iteration = new IterationDBO();
iteration.setNumber(iterationNum);
iteration.setRelease(release);
DatabaseFacade.getInstance().merge(iteration);
}

log.info("reqs="+requirements.size());
Collection<RequirementDBO> iterationReqs = iteration.getRequirements();

//go through and get requirements that are being added to an iteration
for(RequirementDBO req : requirements) {
log.info("looking id="+req.getId());
log.info("inIteration="+req.isInIteration());
log.info("contains="+iterationReqs.contains(req));
if(req.isInIteration() && !iterationReqs.contains(req)) {
log.info("adding="+req.getName());
iteration.addRequirement(req);
} else if(!req.isInIteration() && iterationReqs.contains(req)) {
log.info("removing="+req.getName()+" prev iteration="+req.getIteration());
iteration.removeRequirement(req);
}
}

log.info("req size="+iterationReqs.size());
DatabaseFacade.getInstance().merge(iteration);

Here is my merge method....
public void merge(Object bean) {
EntityManager mgr = mgrFactory.createEntityManager();
mgr.getTransaction().begin();
try {
// RequirementDBO req = (RequirementDBO)o;
// log.info("id="+req.getId()+" version="+req.getVersion()+" name="+req.getName());

mgr.merge(bean);
mgr.getTransaction().commit();
} catch (RuntimeException e) {
mgr.getTransaction().rollback();
log.log(Level.WARNING, "Transaction failed, rolling it back", e);
throw e;
} finally {
mgr.close();
}
}

thanks for any info on my mistake here.
dean


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 7:35 am 
Regular
Regular

Joined: Thu Sep 16, 2004 4:56 pm
Posts: 80
okay, maybe more info would help. I have stripped down the problem to a simple test. The code for all this follows. orphaning a child from the parent does not update the database here such that the child no longer relates to the parent(I am not trying to delete the child, just orphan it).

first the test.....

Code:
   public void testOrphanChildOnPurpose() {
      String child2Name = setupDb();
      
      EntityManager mgr = openSession();
      mgr.getTransaction().begin();
      
      Query q = mgr.createNamedQuery("getParents");

      @SuppressWarnings("all")
      List<ParentDBO> parents = q.getResultList();
      assertEquals("There should be only one", 1, parents.size());

      Query q2 = mgr.createNamedQuery("getChild");
      q2.setParameter("name", child2Name);
      ChildDBO childToRemove = (ChildDBO)q2.getSingleResult();
      
      ParentDBO parent = parents.get(0);
      
      Collection<ChildDBO> children = parent.getChildren();      
      assertEquals("Should be 2 children", 2, children.size());
      
      children.remove(childToRemove);
      
      assertEquals("Should have removed a child", 1, children.size());
      
      mgr.merge(parent);
      
      mgr.getTransaction().commit();
      mgr.close();
   }
   
   private String setupDb() {
      EntityManager mgr = openSession();

      mgr.getTransaction().begin();

      String child2Name="anotherChild";
      ParentDBO parent = new ParentDBO();
      parent.setName("parent");
      ChildDBO child = new ChildDBO();
      child.setName("child");
      parent.addChild(child);
      ChildDBO child2 = new ChildDBO();
      child2.setName(child2Name);
      parent.addChild(child2);   
      
      //in the hibernate logs, this should result in 2 inserts and no updates but results
      //in one update still!!!
      mgr.merge(parent);

      mgr.getTransaction().commit();
      mgr.close();
      return child2Name;
   }


Now the entire ParentDBO bean...
Code:
@Entity
@Table( name = "Parents")
@NamedQueries(
   {
      @NamedQuery(name="getParents", query="SELECT c FROM ParentDBO c")
   })
public class ParentDBO {

   private Long id;
   private int version;
   private String name;
   private Collection<ChildDBO> children;
   
   @Column(name="Id")
   @Id()
   @GeneratedValue(strategy = GenerationType.AUTO)
   public Long getId() {
      return id;
   }
   @SuppressWarnings("all")
   private void setId(Long id) {
      this.id = id;
   }
   
   @Version
   @Column(name="Version", nullable=false)
   public int getVersion() {
      return version;
   }
   @SuppressWarnings("all")
   private void setVersion(int version) {
      this.version = version;
   }
   
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   
   @Column(name="parent_id")
   @OneToMany(mappedBy="parent", cascade = CascadeType.ALL, fetch=FetchType.EAGER)   
   public Collection<ChildDBO> getChildren() {
      if(children == null) {
         children = new ArrayList<ChildDBO>();
      }
      return children;
   }
   public void setChildren(Collection<ChildDBO> children) {
      this.children = children;
   }
   public void addChild(ChildDBO child) {
      if(child == null)
         throw new IllegalArgumentException("child may not be null and was");
      else if(child.getParent() != null)
         child.getParent().getChildren().remove(child);
      
      child.setParent(this);
      getChildren().add(child);
   }
   
   public void removeChild(ChildDBO child) {
      if(child == null)
         throw new IllegalArgumentException("child may not be null and was");
      else if(!getChildren().contains(child))
         throw new IllegalArgumentException("Parent does not contain this child");
      
      child.setParent(null);
      getChildren().remove(child);
   }
}


Now the entire ChildDBO bean....

Code:
@Entity
@Table( name = "Children")
@NamedQueries(
   {
      @NamedQuery(name="getChild", query="SELECT c FROM ChildDBO c WHERE c.name = :name")
   })
public class ChildDBO {

   private Long id;
   private int version;
   private String name;   
   private ParentDBO parent;
   
   @Column(name="Id")
   @Id()
   @GeneratedValue(strategy = GenerationType.AUTO)
   public Long getId() {
      return id;
   }
   @SuppressWarnings("all")
   private void setId(Long id) {
      this.id = id;
   }
   
   @Version
   @Column(name="Version", nullable=false)
   public int getVersion() {
      return version;
   }
   @SuppressWarnings("all")
   private void setVersion(int version) {
      this.version = version;
   }
   
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   
   @ManyToOne
   @JoinColumn(name="parent_id")
   public ParentDBO getParent() {
      return parent;
   }
   public void setParent(ParentDBO parent) {
      this.parent = parent;
   }   
   
   @Override
   public boolean equals(Object rightSide) {
      if(!(rightSide instanceof ChildDBO))
         return false;

      ChildDBO child = (ChildDBO)rightSide;
      if(!id.equals(child.id))
         return false;
      
      return true;
   }

   @Override
   public int hashCode() {
      return (int)(id / 2);
   }   
}
[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 23, 2006 9:09 am 
Regular
Regular

Joined: Thu Sep 16, 2004 4:56 pm
Posts: 80
I finally found out that it turns out what is causing the problem is the @Version fields. Why is this? This should not cause an update after the two inserts as it is all in one transaction. Once I change to not have version, everything works, but I need version fields!!!! is this a bug?
thanks,
dean


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 24, 2006 9:24 am 
Regular
Regular

Joined: Thu Sep 16, 2004 4:56 pm
Posts: 80
anyone know the answer to this????


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