-->
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: Thorny equals/hashCode problem involving cascades
PostPosted: Wed Jul 20, 2005 1:50 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
As recommended in HIA and the reference docs, my objects implement equals and hashCode using 'business key equality', or 'the natural key I would be using if I wasn't using surrogate keys'. This means that they exclude the identifier property (because that breaks sets on save in the well understood way), but they do sometimes include the identifier properties of their associations.

Consider the parent-child example:

Code:
class Parent
{
    Long id;
    Set<Child> children;
}

class Child
{
    Long id;
    Parent parent;
    String name;

    boolean equals(Object rhs)
    {
        //equate on name and parent.getId()
    }
}


The problem arises when a save cascades from parent to child. Hibernate updates both entities identifier properties with the newly generated values, which means the child's hashcode changes (because parent.getId() was null before but it isn't now!) while it is in the parent's set, breaking the set. I basically have to do a refresh() on the root entity to get around this.

Am I missing something here? Is the business key not supposed to include associations? How do you implement equality on a class representing an association table then?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 20, 2005 1:55 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
You are only supposed to use the parent.id in the child.equals() method if it doesn't change when the child has to be saved. Usually thats easier to guarantee than anything else, because most of the time parent/child implies that the parent already exists when the children will be added (HiA's example of Item and Bid should make this clear).


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 20, 2005 2:03 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
Fair enough, that works when establishing a link to a 'reference data' table that rarely or never changes, but how do you implement equality for a many-to-many association class?

Code:
class FooBar
{
    Foo foo;
    Bar bar;
    Boolean flag;

    boolean equals(Object rhs)
    {
        //oh snap
    }
}


It isn't even possible for rows in FOO_BAR to already exist, the foreign key constraints prevent this. You have to create new instances, put them in Foo's and Bar's sets of FooBar, then Hibernate cascades the save to create the association rows and you're back where you started.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 21, 2005 1:31 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
In attempting to solve this problem, I changed those equality computations where the related entity might cascade to compute equality on the association itself rather than its identifier.

Code:
class Parent
{
    Long id;
    Set<Child> children;
}

class Child
{
    Long id;
    Parent parent;
    String name;

    boolean equals(Object rhs)
    {
        //equate on name and parent (not parent.getId())
    }
}


Unfortunately, this just binds the breakage to a change in the associated object's natural key instead of its identifier, which soundly defeats the point. The identifier is at least guaranteed to be the same after the initial save, so it's still a better solution to just reload the entity that one time.


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.