-->
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.  [ 8 posts ] 
Author Message
 Post subject: A question regarding the <list> mapping
PostPosted: Wed May 25, 2005 6:08 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
I've run into a problem with my <set> mappings. Basically, I have a number of tables representing three-way associations. These tables consist of a surrogate primary key (organization standard) as well as three foreign keys with a database uniqueness constraint. I map these in their own file, and as their own class using many-to-one in the traditional way. However, since I cannot use the primary key itself in the equality computation (as HIA instructs), and I cannot use any of the associations either (because equals or hashCode would cause lazy fetching of associations), the result is that there is nothing to base the result of these methods on. This means that equals() always returns true, and that only one result from a query which may have many results ever shows up in my set. Clearly, this is no good.

A solution might be to expose the actual FK values (as opposed to the associations) somehow (I'm not sure this is possible) and use those. I don't really like this solution for what should be obvious reasons.

Another solution might be to use a Map and map the primary key value to the 'index'. This would work, but it would cause new transient instances with null keys to overwrite each other even if they different in their property values, in addition to not insuring that a transient instance with property values that matched another persistent or detached instance already in the map could not be introduced into the map. (In addition to the fact that a map keyed by an integer is really just a needlessly heavyweight list)

What I'd really like to do is use a <list> mapping in order to make my model consistent with the return type of hibernate query APIs. I've been reading HIA/ref docs, but it is not clear whether an 'index' value for a <list> mapping which ends up being 543,931 (possibly as a result of using the pk column as the index) implies that the list will have 543,930 elements before the requested one all set to null. The documentation suggests adding a new 'sequence' column to your table to use for the index, but I don't see what this solves if you already have a numeric identity pk -- they'll just end up running in parallel. What'd really be necessary is some way to have a 'query local' index, not a 'table wide' index, though this may not actually be how the <list> mapping works.

Your thoughts on this issue?


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 26, 2005 11:02 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
how does your mapping look like ?

Do you know someObject.getId() does not initialize a proxy ? (and thus can be used in equals IFF the object is always persistent when associated with the obj)
Do you know that its often better to map the composite keys as a normal property and then have ordinary many-to-one with update/insert set to false ?


-max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 10, 2005 2:06 am 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
1.
Apologies for seeming to abandon this thread, I thought it had died with no replies.

I was aware that getId() would not initialize a proxy, but couldn't see a way to make use of it. This is because I use commons-lang reflection EqualsBuilder to implement a single equals()/hashCode() in my case class which is then used for all child classes. The EqualsBuilder works by recursively calling equals() on every pair of references in the graphs of the compared objects until it is stopped by lack of non-transient member variables in the leaf classes. Ideally we would have the EqualsBuilder distinguish between the 'root object' on which the original equals() call was made (like item.equals(anotherItem)) and the objects it holds references to that the recursion will compare, and apply different strategies for equivalence computation based on that criteria. The root would have its identifier property excluded, while the recursed objects would not. Commons-lang does not support this kind of usage however, and implementing it would take a considerable amount of work, so that was out.

I did find a simple and easy way to do this without hacking commons-lang. By simply declaring a foreign key member variable in parallel to the many-to-one association,

class Item {
private transient Person person;
private Long personId;
}

then setting personId in the setPerson() method, I can get the EqualsBuilder to generate correct results. The foreign key itself isn't mapped and doesn't even need any accessor methods.

2.
With regards to your second comment, I am not sure what you mean. I don't have any composite keys in my model, nor do I have anything mapped with insert/update set to false. The 'three way association' I was talking about looks something like this:

class Foo {
Set<FooBarBaz> fbz;
}

class Bar {
Set<FooBarBaz> fbz;
}

class Baz {
Set<FooBarBaz> fbz;
}

class FooBarBaz {
Foo foo;
Bar bar;
Baz baz;
}

This works fine for my purposes now.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 10, 2005 5:27 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
then dont use EqualsBuilder!

putting fkid's together with your entityref (or just the fkid) is far more evil then writing a equals method.

EqualsBuilder in this case will almost for certain be wrong and highly in inefficient!

And besides you should choose your equals comparison wisely - not something you can do generically in a superclass and keep the correct semantics.

-max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 10, 2005 10:38 am 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
Even if the fk is private, has no accessor methods, and is inexorably bound to the entity itself?

It seems to be working for me. Why do you say that it is wrong?

Code:
class Person
{
   private transient Person supervisor;
   private Long supervisorId;

   //This is the ONLY method referencing supervisorId
   public void setSupervisor(Person _supervisor)
   {
      supervisor = _supervisor;
      supervisorId = supervisor == null ? null : supervisor.getId();
   }
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 10, 2005 10:56 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
why not have clear code that does:

Code:
class Person
{
   private Person supervisor;
 
   public void setSupervisor(Person _supervisor)
   {
      supervisor = _supervisor;
   }

// and then use supervisor.getId() whereever you need the id ?
}


introducing two variables where one is clearly enough increases the chance of errors with 100%

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 10, 2005 11:33 am 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
Right, that would be ideal. However, as discussed above, making that approach work with EqualsBuilder would mean modifying it significantly. If that is not possible or worthwhile, I believe my solution is a decent enough compromise.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 10, 2005 1:35 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
I totally disagree with you - but that's your right ,)

-max

_________________
Max
Don't forget to rate


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