-->
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.  [ 15 posts ] 
Author Message
 Post subject: Map two sets to same table?
PostPosted: Tue Mar 03, 2009 12:41 am 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
I'm unclear on how to create the mappings for a situation. This is not my exact use case, but is a simplified illustration of what I'm trying to do:

I have a Dog entity that contains an id and name property.

I have a Breeder entity that contains a set of Dogs. These are the Dogs that the Breeder owns.

Now, I need a way to save some state across logins to the system. Breeders can select certain Dogs from their list of Dogs, and I need the system to remember which Dogs they have selected.

I don't want to add a "selected" property to Dog.

selectedDogs is always a sub-set of dogs. It could be the entire set of the breeder's dogs or no dogs or anything in between. But it will never contain any other Dog that is owned by another Breeder.

I currently have this implemented where Breeder has two sets, dogs and selectedDogs. These both map to separate tables breederDogs and breederSelectedDogs.

I want to implement it so that I only have one table (breederDogs) where both sets map to the same table and that table has an extra boolean property for selected.

But without a property in an entity class, I'm unsure how to do that. How do I create a mapping to the same table for two sets within the same entity? And how do I add an additional property to the table for one of those sets, without that property being part of an entity? Do I need to create another entity for this (like DogSelection which contains dog and selected)?

I feel like I'm missing something simple here. Or is what I'm trying to do not possible?

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 03, 2009 3:12 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
An entity like DogSelection could be a solution. Do you use a join-table or a join-column in dogtable?
If you use a Join-column: How about just adding another join-column for the breeder's selection? Thats not the nicest solution as dogs could possibly be selected by other breeders than their own, but it's an easy solution.

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 03, 2009 3:28 am 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
mmerder wrote:
An entity like DogSelection could be a solution. Do you use a join-table or a join-column in dogtable?
If you use a Join-column: How about just adding another join-column for the breeder's selection? Thats not the nicest solution as dogs could possibly be selected by other breeders than their own, but it's an easy solution.


Here are sample mappings for this example. I end up with four tables: dogs, breeders, breederDogs, and breederSelectedDogs:

Code:
    <class name="Dog" table="dogs">
        <cache usage="read-write"/>
        <id name="id" column="id">
            <generator class="identity"/>
        </id>

        <property name="name" length="40"/>
        <many-to-one name="breeder" abstract="true" not-null="true" cascade="none" />
     </class>


Code:
    <class name="Breeder" table="breeders">
        <cache usage="read-write"/>
        <id name="id" column="id">
            <generator class="identity"/>
        </id>

        <property name="first" length="25"/>
        <property name="middle" length="25"/>
        <property name="last" length="50"/>
        <property name="username" length="50"/>
        <property name="password" length="50"/>

        <list name="selectedDogs" table="breederSelectedDogs" cascade="all,delete-orphan">   
            <key column="person" />
         <list-index column="idx" />
            <many-to-many class="Dog" column="dog" />
        </list>
        <list name="dogs" table="breederDogs" cascade="all,delete-orphan">   
            <key column="breeder" />
         <list-index column="idx" />
            <many-to-many class="Dog" column="dog" />
        </list>
    </class>


I'm unclear on what you are suggesting I do. Would you be able to clarify further?

I guess the issue for me with adding a DogSelection entity is that I don't need it in my pure java logic. Or with adding another property to Dog or Breeder. I have two sets in my Breeder and I can get everything I need. So it seems like there should be a way to do it with Hibernate that I'm just not aware of.

Thanks for your help!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 03, 2009 7:25 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
You can use <filter> for filtering collections. I dont know much about <list> so I have used <set>:
Code:
<hibernate-mapping>
   <class name="Dog" table="DOG">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
   </class>

   <class name="Breeder" table="BREEDER">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
      <set name="dogs" table="BREEDERDOG">
         <key column="BREEDER_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
      <set name="selectedDogs" table="BREEDERDOG">
         <key column="BREEDER_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
         <filter name="breederSelectedDogs" condition="SELECTED=1"></filter>
      </set>
   </class>
   <filter-def name="breederSelectedDogs"/>
</hibernate-mapping>

In your java code:
Code:
      session.enableFilter("breederSelectedDogs");
      Breeder br = (Breeder) session.get(Breeder.class, 1L);

But why dont you want to map the selected property? If you dont map it then how will you update the property in DB?

And also what is the realtion b/w Dog and Breeder? Is it MTO or MTM? Coz in the Dog entity you have mapped it as MTO and in breeder you are using MTM tag.

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 03, 2009 6:24 pm 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
litty -- thanks for your reply. The mappings were just an illustration and not copied from a running application, so I apologize if they were inaccurate.

Here is what I would like to accomplish. How would you do this?

  • Breeder is a user on the system
  • Breeder contains a set of Dogs owned by the breeder that are unique -- no other breeder owns these dogs
  • Each Dog has a reference back to its breeder
  • A user (breeder) can select a sub-set of their Dogs (and only their dogs), and this selection is maintained across multiple login sessions. The selection can be changed by the user at any time.

To do this in the POJOs is fairly simple:
Code:
public class Breeder implements Serializable
{
    private Long id;
    private String username;
    private String password;
    private Set<Dog> dogs = new HashSet<Dog>();
    private Set<Dog> selectedDogs = new HashSet<Dog>();
}

public class Tag implements Serializable
{
    private Long id;
    private String name;
    private Breeder breeder;
}


  • I have this working by having a separate join table for Breeder.dogs and for Breeder.selectedDogs.
  • But this seems inefficient since selectedDogs is simply a sub-set of dogs.
  • So I'm looking for a way to share one join table for both sets.
  • To do that I need to add another property to the table that indicates if it is included in the selectedDogs set. This is what I don't know how to do, or if this feature even exists.
  • Since the java code works as is, without need for additional classes or properties, I was thinking I can get it to work in hibernate too.


I hope this clarifies things! Thanks again for the help.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 3:01 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
Well as you said the most efficient way is to have a flag in the Dog table to indicate that this dog is selected. Now i dont understand why you dont want to have a property in the Dog entity corresponding to this. Coz if you dont have a property corresponding to the flag you wont be able to set this property in DB using hibernate and u ll hav to use native SQL.

So the best to to do this is have a column SELECTED in the DOG table and have a corresponding property in the Dog POJO. Now you can map the selectedDogs list using a "where" attribute.

Code:
public class Dog implements Serializable
{
    private Long id;
    private String name;
    private Breeder breeder;
    private boolean selected;
}

<class name="Breeder" table="BREEDER">
   ..............
   ..............
   <set name="selectedDogs" table="DOG" cascade="save-update" fetch="join" where="SELECTED=1">
      <key column="BREEDER_ID" />
      <one-to-many class="Dog" />
   </set>
</class>

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 6:04 am 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
Litty,

Thanks! This will work for me. I guess the "where" attribute is what I was looking for.

My only reservation with this solution is that it isn't necessary from a pure java perspective. There is no reason to have a selected property in Dog to make the relation work in java alone. It is only once Hibernate is introduced that this additional property becomes necessary. With Java alone, just having the sets Breeder.dogs and Breeder.selectedDogs is enough with no need for a selected property in Dog.

My understanding of hibernate was that my regular pojo business logic should be able to be persisted without modifying the pojos (as long as certain requirements are maintained in the pojo, such as an id property, and that collection interfaces are used instead of concrete collections, etc.)

I'm not saying I can't use this solution or that I won't, I was just thinking that there would be a way to do it without adding this property.

Thanks again. I'm marking this post as solving my problem, but I would still welcome any comments on how to make this work without modifying the Dog class.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 7:32 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
I am afraid I dont know any method by which you can make hibernate update your DOG.SELECTED column just by adding the entity to selectedDogs collection. What you can do at most is set/reset the Dog.selected attribute in your add/removeToSelectedDog() methods.

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 8:04 am 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
littypreethkr wrote:
I am afraid I dont know any method by which you can make hibernate update your DOG.SELECTED column just by adding the entity to selectedDogs collection. What you can do at most is set/reset the Dog.selected attribute in your add/removeToSelectedDog() methods.


OK, thanks. I still don't think you're quite getting my point. I am saying that the Dog.selected property doesn't need to be part of the pojo if I was implementing a plain java program (without any hibernate involved). I would know which Dogs are selected simply by iterating the Breeder.selectedDog set. No Dog.selected property would need to exist.

My hope was that I could create a hibernate mapping to solve this relation without requiring a modification to the domain model. But I'm starting to think what I'm imagining isn't possible anyway. So I'll just drop it now.

Thanks again for everything!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:02 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
As I said in my first post, you could just map the selected collection to another join-column. That way your model would not change and the only thing you'd have to do is add and remove dogs from the selected-collection.
Of course this would not prevent a dog from being in another breeder's selection but that problem could also be solved programmatically.

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:18 am 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
mmerder wrote:
As I said in my first post, you could just map the selected collection to another join-column. That way your model would not change and the only thing you'd have to do is add and remove dogs from the selected-collection.
Of course this would not prevent a dog from being in another breeder's selection but that problem could also be solved programmatically.


Would you mind illustrating this solution with an example mapping file?

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:30 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
It's almost the same as before:
Code:
<hibernate-mapping>
   <class name="Dog" table="DOG">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
   </class>

   <class name="Breeder" table="BREEDER">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
      <set name="dogs" table="BREEDERDOG">
         <key column="BREEDER_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
      <set name="selectedDogs" table="BREEDERDOG">
         <key column="BREEDER_SELECTION_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
   </class>
   <filter-def name="breederSelectedDogs"/>
</hibernate-mapping>


But as described, the problem with this solution is, that it is not a real subset of the breeders dogs.

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:32 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
It's almost the same as before:
Code:
<hibernate-mapping>
   <class name="Dog" table="DOG">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
   </class>

   <class name="Breeder" table="BREEDER">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
      <set name="dogs" table="BREEDERDOG">
         <key column="BREEDER_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
      <set name="selectedDogs" table="BREEDERDOG">
         <key column="BREEDER_SELECTION_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
   </class>
   <filter-def name="breederSelectedDogs"/>
</hibernate-mapping>


But as described, the problem with this solution is, that it is not a real subset of the breeders dogs.

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 9:34 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
It's almost the same as before:
Code:
<hibernate-mapping>
   <class name="Dog" table="DOG">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
   </class>

   <class name="Breeder" table="BREEDER">
      <id name="id" column="ID" type="long">
         <generator class="native"></generator>
      </id>
      <property name="name" type="java.lang.String" column="NAME" />
      <set name="dogs" table="BREEDERDOG">
         <key column="BREEDER_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
      <set name="selectedDogs" table="BREEDERDOG">
         <key column="BREEDER_SELECTION_ID" />
         <many-to-many class="Dog" column="DOG_ID" />
      </set>
   </class>
   <filter-def name="breederSelectedDogs"/>
</hibernate-mapping>


But as described, the problem with this solution is, that it is not a real subset of the breeders dogs.

_________________
-----------------
Need advanced help? http://www.viada.eu


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 04, 2009 5:40 pm 
Beginner
Beginner

Joined: Fri Mar 21, 2008 8:07 pm
Posts: 23
mmerder,

Thanks, I see what you are getting at now. Your right though, it's not quite an ideal solution. I'll have to think about whether doing this would be better than modifying my domain model and adding Dog.selected.

Tauren


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