-->
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.  [ 7 posts ] 
Author Message
 Post subject: PostUpdateEvent on Join Table?
PostPosted: Thu Apr 12, 2007 11:23 pm 
Newbie

Joined: Wed Sep 06, 2006 11:49 am
Posts: 5
Hiya.

I can't find any documentation on how to receive PostUpdate/PostInsert events on a many-to-many relationship. Is this possible?

I have 2 classes - LiveMember and Genre. They share a many-to-many relationship, and I need notification when my LiveMember changes any of his Genres. However, since all inserts/updates/deletes occur in the join table, no event is ever fired to the LiveMember or Genre object.

My [Pre|Post][Update|Insert]Listeners are all registered programatically, and fire appropriately when changes are made to the entity's direct fields.

Anyone with experience in this?

Thanks in advance!

S,
ALR

Hibernate version:
Bundled w/ JBoss EJB3 RC9 Patch 1

Mapping documents:
Annotations

Code:
@Entity
public class Genre{
...
        @ManyToMany(mappedBy = "genres")
   public Collection<LiveMember> getLiveMembers() {
      return liveMembers;
   }
}


Code:
@Entity
public class Band{
...
       @ManyToMany
   @JoinTable(name = "sync_live_join_band_genre")
   public Collection<Genre> getGenres() {
      return genres;
   }
}


Name and version of the database you are using:
MySQL 5.0.27 Community

The generated SQL (show_sql=true):
Code:
145 Prepare     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (?, ?)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 101)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 102)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 103)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 104)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 106)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 107)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 108)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 109)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 110)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 111)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 112)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 113)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 114)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 115)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 116)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 117)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 118)
                    145 Execute     [172] insert into sync_live_join_livemember_genre (liveMembers_id, favoriteGenres_id) values (10000, 100)
                    145 Query       XA END 0x3233322e3136342e31322e3231362e696e76697369626c6568616e642e6e65742f313532,0x32,0x101
                    145 Query       XA PREPARE 0x3233322e3136342e31322e3231362e696e76697369626c6568616e642e6e65742f313532,0x32,0x101
                    145 Query       XA COMMIT 0x3233322e3136342e31322e3231362e696e76697369626c6568616e642e6e65742f313532,0x32,0x101

[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 12, 2007 11:25 pm 
Newbie

Joined: Wed Sep 06, 2006 11:49 am
Posts: 5
There's some discrepancy posted above with LiveMember and Band; both have many-to-many with Genre, but I think the point gets across.

I'd just like the event fired on changed to the join tables. Possible?

S,
ALR


Top
 Profile  
 
 Post subject:
PostPosted: Sat Apr 14, 2007 8:12 pm 
Senior
Senior

Joined: Tue Mar 09, 2004 2:38 pm
Posts: 141
Location: Lowell, MA USA
Andy,

Are these classes using versioning? While it may not directly solve your problem, a version value should trigger an up update on entity you want. When the collection is modified, the version value should increment resulting in an update on the entity as well as the join table. Hope this helps.

Ryan-

_________________
Ryan J. McDonough
http://damnhandy.com

Please remember to rate!


Top
 Profile  
 
 Post subject:
PostPosted: Sat Apr 14, 2007 9:06 pm 
Senior
Senior

Joined: Tue Mar 09, 2004 2:38 pm
Posts: 141
Location: Lowell, MA USA
Actually, I have a few other questions:

1.) What does the code look like that manipulates the Genre & LiveMemeber?
2.) What does the code look like that handles the adding and removal of objects on the Genre & LiveMemeber objects?

It would be helpful to see more of the entity code.

Ryan-

_________________
Ryan J. McDonough
http://damnhandy.com

Please remember to rate!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 15, 2007 4:02 pm 
Newbie

Joined: Wed Sep 06, 2006 11:49 am
Posts: 5
Thanks for having my back here, Ry.

I'd previously been doing versioning by way of a top-level @MappedSuperclass containing "created" and "modified" date fields, were were kept in check by @PrePersist and @PreUpdate. This was to easily facilitate calculating deltas in the DB over time for export to an external reporting DB.

Adding JPA Optimistic locking using @Version (per your suggestion) absolutely did just the trick; once the Collection is modified, this field changes and in turn triggers the Lifecycle Events I needed on the LiveMember entity.

Couple caveats to note:

Once using @Version in your entities, you can't do (in your business logic):

Code:
LiveMember currentMemberProfile = [something populated]
currentMemberProfile.getFavoriteGenres().clear();
      if (liveMember.getFavoriteGenres() != null) {
         for (GenreTO genre : liveMember.getFavoriteGenres()) {
            currentMemberProfile.getFavoriteGenres().add(new Genre(genre.getId));
         }
      }


...because you will receive a Transient/Detatched Object exception. I liked this approach because it did not involve a SELECT to the DB to retrieve the Genre when we already know the only piece of information we need, the ID. Instead the code must look like:

Code:
LiveMember currentMemberProfile = [something populated]
currentMemberProfile.getFavoriteGenres().clear();
      if (liveMember.getFavoriteGenres() != null) {
         for (GenreTO genre : liveMember.getFavoriteGenres()) {
            Genre g = this.getLiveUserDar()
                  .find(Genre.class, genre.getId());
            currentMemberProfile.getFavoriteGenres().add(g);
            g.getLiveMembers().add(currentMemberProfile);
         }
      }


...which does cause some unnecessary selects before updates, but hey, at least my events are now firing in the many-to-many, and that was my main concern.

Owe you a beer.

S,
ALR


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 15, 2007 4:10 pm 
Newbie

Joined: Wed Sep 06, 2006 11:49 am
Posts: 5
One note for clarification:

Code:
getLiveUserDar()

...is an implementation of the DAR (Data Access Repository) pattern (http://domaindrivendesign.org/discussion/messageboardarchive/DAOVersusRepository.html ) , and this paricular one calls upon the EM. So pretend "getLiveUserDar()" is "this.getEntityManager()".

S,
ALR


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 15, 2007 4:13 pm 
Senior
Senior

Joined: Tue Mar 09, 2004 2:38 pm
Posts: 141
Location: Lowell, MA USA
You can owe me two beers :) You can actually avoid making an extra query if you do something like this:

Code:
Genre genre = entityManager.getReference(Genre.class,genre.getId);
currentMemberProfile.getFavoriteGenres().add(genre);


By calling getReference(), you don't actually load the entity but it's enough to satisfy the relationship. As long as you don't access any other property of the Genre instance, no SQL is actually executed. It's several times more efficient than using find() in this case.

Ryan-

_________________
Ryan J. McDonough
http://damnhandy.com

Please remember to rate!


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