-->
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.  [ 11 posts ] 
Author Message
 Post subject: saving many-to-many associations
PostPosted: Fri Jan 06, 2006 5:35 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
i'm making a simple helpdesk ticket application as a means of learning hibernate and other technologies and generally driving myself mad...

right now i can create a Ticket, which has a Set of related Tags. a Ticket can have 0..* Tags and vice-versa. i've modeled this in the database by means of a join table with ticket_id and tag_id

the problem i'm having is that when i create tickets with tags, the tickets and tags are saved in their respective tables but the join table is not populated, apparently since there is no Ticket.id when i call save(). if i modify an existing ticket the join table IS updated.

the order of operations is thus:

create Ticket, populate data
create Tags, add to Ticket
save Tags
save Ticket

i've also tried

create Ticket, populate datas
save Ticket
create Tags, add to Ticket
save Tag

both with the same result: join table is not updated.

any ideas?

Hibernate version: 3.1rc2

Mapping documents:
Code:
Ticket:
<?xml version="1.0"?>
<!DOCTYPE
   hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="com.jeffemminger.tracker.model.Ticket" table="tickets">
      <id name="id" column="id">
         <generator class="native"/>
      </id>
      <property name="title" type="string">
         <column name="title" not-null="true"/>
      </property>
      <property name="description" type="string">
         <column name="description" not-null="true"/>
      </property>
      
      <many-to-one name="owner" column="owner_user_id"
         class="com.jeffemminger.tracker.model.User" not-null="true"/>
      
      <set name="tags" table="tags_tickets" lazy="true" inverse="true"
         cascade="save-update">
         <key column="ticket_id"/>
         <many-to-many class="com.jeffemminger.tracker.model.Tag"
            column="tag_id"/>
      </set>
   </class>
</hibernate-mapping>

Tag:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="com.jeffemminger.tracker.model.Tag" table="tags">
      <id name="id" column="id">
         <generator class="native"/>
      </id>
      <property name="name" type="string">
         <column name="name" not-null="true"/>
      </property>
      
      <set name="tickets" table="tags_tickets" lazy="true" inverse="true"
         cascade="save-update">
         <key column="tag_id"/>
         <many-to-many class="com.jeffemminger.tracker.model.Ticket"
            column="ticket_id"/>
      </set>
      
   </class>
</hibernate-mapping>




Name and version of the database you are using: mysql 4.0.22

The generated SQL (show_sql=true):
Hibernate: insert into tags (name, created_on, updated_on) values (?, ?, ?)
Hibernate: insert into tickets (title, description, created_on, updated_on, owner_user_id) values (?, ?, ?, ?, ?)


Top
 Profile  
 
 Post subject: INVERSE="true"
PostPosted: Fri Jan 06, 2006 7:38 pm 
Newbie

Joined: Thu Jan 05, 2006 7:33 pm
Posts: 13
Hi Jemminger

from the mappings u posted it seems that INVERSE="true" is duplicated. Remove one so that the other manages the association.

<set name="tags" table="tags_tickets" lazy="true" inverse="true"
cascade="save-update">
<key column="ticket_id"/>
<many-to-many class="com.jeffemminger.tracker.model.Tag"
column="tag_id"/>
</set>


<set name="tickets" table="tags_tickets" lazy="true" inverse="true"
cascade="save-update">
<key column="tag_id"/>
<many-to-many class="com.jeffemminger.tracker.model.Ticket"
column="ticket_id"/>
</set>

Good luck and let us know how u go

Michael


Top
 Profile  
 
 Post subject: docs
PostPosted: Fri Jan 06, 2006 7:44 pm 
Newbie

Joined: Thu Jan 05, 2006 7:33 pm
Posts: 13
heres the docs reference too:

http://www.hibernate.org/hib_docs/v3/re ... l-join-m2m

Michael


Top
 Profile  
 
 Post subject: re: inverse="true"
PostPosted: Fri Jan 06, 2006 7:47 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
ah... just looked it up in a hibernate book, and it looks like i should set inverse="true" on the Tag but not on the Ticket, making the Ticket own the relationship, and it should save the Tag association automatically. i'll give that a go and see if it works. thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 10, 2006 5:19 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
alright, i fixed the mapping so that only the Tag has inverse="true" but still nothing is being inserted into the join table.

here's the code doing the work:

Code:
HibernateUtil.beginTransaction();
createNewTags();
ticketdao.add(getTicket());
// servlet filter commits any transactions


and the code for createNewTags:
Code:
private void createNewTags() {
String newTags = getNewTags();
if (newTags != null) {
  String[] tags = newTags.split(",");

  // for each new tag, create and add to ticket
  for (String sTag : tags) {
   if (sTag != null && sTag.trim().length() > 0) {
    try {
     Tag oTag = tagdao.add(new Tag(sTag));
     getTicket().addTag(oTag);
    }
    catch (DAOException e) {
     log.warn("createNewTags", e);
    }
   }
  }
}
}



all operations are under the same transaction. if i inspect the new ticket inside ticketdao.add(), i can see the Tags associated with it and they do have IDs.

not sure what else to try here.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 10, 2006 6:19 pm 
Expert
Expert

Joined: Tue Nov 23, 2004 7:00 pm
Posts: 570
Location: mostly Frankfurt Germany
your code runs here, when I take away the inverse=true in the Ticket mapping.

I set manually
Code:
Ticket     m = new Ticket();
  Tag tag = new Tag();
  tag.setName("ein TAg");
  m.getTags().add(tag);


Your problem may be somewhere else now. Please check if you add the tag to the ticket on the ticket side. You should set it on both sides, otherwise your session objects will not be up to date. Hibernate will not add the Ticket to the Tag set automatically.

But to write the data in the relation table, you must set it on the ticket side.

Regards Sebastian

Please rate, if this helped.

_________________
Best Regards
Sebastian
---
Training for Hibernate and Java Persistence
Tutorials for Hibernate, Spring, EJB, JSF...
eBook: Hibernate 3 - DeveloperGuide
Paper book: Hibernate 3 - Das Praxisbuch
http://www.laliluna.de


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 12, 2006 4:57 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
still having the same problem... adding a new Tag to a new Ticket does not update the join table.

here's the add() method from my Ticket DAO:
Code:
public Ticket add(Ticket ticket) throws DAOException {
log.debug("entered add("+ticket.getId()+")");
try {
  Date date = new Date();
  ticket.setCreatedOn(date);
  ticket.setUpdatedOn(date);
  for (Tag tag : ticket.getTags()) {
   log.debug("in add(), tag: " + tag.getId() + ", " + tag.getName());
  }
  HibernateUtil.getSession().save(ticket);
  [color=red][b]return ticket;[/b][/color]
}
catch (HibernateException e) {
  String msg = "The TicketDAO could not create ticket.";
  log.error(msg, e);
  throw new DAOException(msg, e);
}
}


i set a breakpoint at the "return ticket" line and ran the app in debug mode, and indeed the new Ticket does have one Tag in its collection, and both the new Ticket and new Tag have an id at this point yet hibernate does not issue sql for the join table insert.

still this only happens when working with a new Ticket... if i edit an existing Ticket, the join table is updated properly.

i can post the whole Tapestry page that's performing the work if it helps


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 12, 2006 5:57 pm 
Expert
Expert

Joined: Tue Nov 23, 2004 7:00 pm
Posts: 570
Location: mostly Frankfurt Germany
Please try a simple
transaction begin
set ...

transaction commit

I tried your mappings and they worked. Of course I may have incidentely changed anything. but I do not think so.
If a clear transaction works, you only have to look through your code. May be you are catching an Exception somewere or the commit is not issued.

Regards Sebastian

_________________
Best Regards
Sebastian
---
Training for Hibernate and Java Persistence
Tutorials for Hibernate, Spring, EJB, JSF...
eBook: Hibernate 3 - DeveloperGuide
Paper book: Hibernate 3 - Das Praxisbuch
http://www.laliluna.de


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 12, 2006 6:33 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
i tried this and it did not work:
Code:
Ticket testTicket = new Ticket();
testTicket.setTitle("test ticket");
testTicket.setDescription("description");
testTicket.setOwner(userdao.get(new Long(1L)));

Tag testTag = new Tag("test tag");

tagdao.add(testTag);
ticketdao.add(testTicket);

testTicket.addTag(testTag);
testTag.addTicket(testTicket);


the two objects are saved to the database but the join table is not updated.
my servlet is beginning a transaction and committing automatically.

i'm not seeing any exceptions thrown.

i also tried adding the related tag to the ticket first like so
Code:
Ticket testTicket = new Ticket();
testTicket.setTitle("test ticket");
testTicket.setDescription("description");
testTicket.setOwner(userdao.get(new Long(1L)));

Tag testTag = new Tag("test tag");

testTicket.addTag(testTag);
testTag.addTicket(testTicket);

tagdao.add(testTag);
ticketdao.add(testTicket);


but this threw an exception since the tag was a non-persistent property at that point.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 13, 2006 4:33 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
grr... i tried the above test code in a stand alone class and it worked properly. i'll try and track down the difference in my page class


Top
 Profile  
 
 Post subject: [SOLVED]
PostPosted: Fri Jan 13, 2006 5:03 pm 
Newbie

Joined: Fri Jan 23, 2004 5:19 pm
Posts: 13
AAAARGH!!!!!

i love it when you finally find the solution, and the solution is that you're an idiot.

i forgot to add the HibernateFilter that commits after every request to web.xml... put that in place and all is right with the world. i take back all those nasty thoughts i had towards hibernate :-)


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