-->
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.  [ 14 posts ] 
Author Message
 Post subject: Eager (left outer join) loading non-distinct cascade entries
PostPosted: Wed Mar 11, 2009 12:21 am 
Beginner
Beginner

Joined: Tue Mar 10, 2009 11:50 pm
Posts: 23
My model class has a cascade relation to one of its child class and the fetch type is eager

public class ServiceModelVO implements java.io.Serializable {

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "serviceModel")
public Set<FeatureModelVO> getFeatureModels() {
return this.featureModels;
}


}


When i retreive all the servciemodelVO entries from database

Criteria serviceModelCriteria = session.createCriteria(ServiceModelVO .class);
serviceModelCriteria .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

List<ServiceModelVO> serviceModelList = serviceModelCriteria.list();

I get distinct entries for all sevice models, but where as the entries for the childs - featuremodel are non distinct and are duplicated.

How to specify in hibernate to retrieve even the cascade entries as distinct. Shouldn't it be done implicitly by hibernate


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 11, 2009 12:43 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
Your FeatureModelVO collection is a Set. Then how come it is duplicated?

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 11, 2009 4:23 am 
Senior
Senior

Joined: Wed Sep 19, 2007 9:31 pm
Posts: 191
Location: Khuntien (Indonesia)
yup, if you use set, your data shouldn't be duplicated. Try to print out your data.

It's better if you override equals and hashcode in FeatureModelVO


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 11, 2009 7:17 am 
Beginner
Beginner

Joined: Tue Mar 10, 2009 11:50 pm
Posts: 23
Thanks for the reply. I did a small test on the SET. Actually, SET eliminates the duplication of adding the same object twice. That means the SET avoids the duplication based on the object reference. However different instances of the class will have different references. Though they satisfy the equals() condition, the references are different, hence SET can hold all those different instances. So, Hibernate must be creating the multiple instances in this case and all those are added into the SET.

It would be nice if Java provides another API which can check the equals of given object against its contained objects. OR Hibernate iterates through the Set and checks equals of a given object against its contained objects and add to the SET accordingly.

Here is a sample test code

import org.apache.commons.lang.builder.EqualsBuilder;


public class SampleClass {

private DependentClass dc;
private String ID;
public SampleClass() {

}

public String getID() {
return this.ID;
}

public void setID(String ID) {
this.ID = ID;
}

public String getString(String str) {

return dc.getString(str);

}

public boolean equals(Object obj) {

if (obj instanceof SampleClass) {
SampleClass sc = (SampleClass) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(getID(), sc.getID());
System.out.println(builder.isEquals());
return builder.isEquals();
}
return false;
}
}


import java.util.HashSet;

public class Test {

public static void main(String[] arg) {

HashSet set = new HashSet();

SampleClass obj1 = new SampleClass();
SampleClass obj2 = new SampleClass();
SampleClass obj3 = new SampleClass();

if (obj1.equals(obj2)) {
System.out.println("obj1 and obj2 are equal");
} else {
System.out.println("obj1 and obj2 are not equal");
}

if(! set.contains(obj1))
set.add(obj1);

if(! set.contains(obj2))
set.add(obj2);

if(! set.equals(obj3))
set.add(obj3);

set.add(obj1);
set.add(obj2);
set.add(obj3);

System.out.println(set.size());

}

}

The result is
--------------
obj1 and obj2 are equal
3


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 11, 2009 8:12 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
No. Set uses the equals method only to see for equality. The problem is that you dont have the hashcode implementation. Do remember the semantics of hashcode method - If obj1.equals(obj2) is true then obj1.hashcode() == obj2.hashcode() should also be true. But the reverse need not be true.

Try this test:

Code:
public class TestVO {

   long id;
   String value;

   public TestVO() {}

   public TestVO(long id) {
      super();
      this.id = id;
   }

   public long getId() {
      return id;
   }

   public String getValue() {
      return value;
   }

   public void setId(long id) {
      this.id = id;
   }

   public void setValue(String value) {
      this.value = value;
   }

   @Override
   public boolean equals(Object obj) {
      if(!(obj instanceof TestVO)) {
         return false;
      }
      TestVO vo = (TestVO)obj;
      if(vo.getId()!= id)
         return false;
      return true;
   }

   @Override
   public int hashCode() {
      return new Long(id).hashCode();
   }
}


Code:
public class TestSetEquals {

   public static void main(String[] args) {
      TestVO vo1 = new TestVO(1);
      TestVO vo2 = new TestVO(1);
      TestVO vo3 = new TestVO(2);

      if (vo1.equals(vo2)) {
         System.out.println("vo1 and vo2 are equal");
      } else {
         System.out.println("vo1 and vo2 are not equal");
      }
      
      HashSet set = new HashSet();
      if(!set.contains(vo1)) {
         set.add(vo1);
      }
      if(!set.contains(vo2)) {
         set.add(vo2);
      }
      if(!set.contains(vo3)) {
         set.add(vo3);
      }
      
      set.add(vo1);
      set.add(vo2);
      set.add(vo3);
      System.out.println(set.size());
   }
}

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 11, 2009 9:13 am 
Senior
Senior

Joined: Wed Sep 19, 2007 9:31 pm
Posts: 191
Location: Khuntien (Indonesia)
yup, littypreethkr is correct. Set will use equals and hashCode methods to compare the object.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 12:39 am 
Beginner
Beginner

Joined: Tue Mar 10, 2009 11:50 pm
Posts: 23
Hi thanks for the reply

If i implement the hash code , set is avoiding adding duplicates and it works fine.

But during insertion of cascade entries hibernate is trying to fetch the hashcode, since the hashcode is built on featureId which is not yet generated; i am getting a null pointer exception.

@Override
public boolean equals(Object obj) {
if(!(obj instanceof FeatureModelVO)) {
return false;
}
FeatureModelVO featureModelVO = (FeatureModelVO) obj;
if(featureModelVO.getFeatureId() != getFeatureId()) {
return false;
}
return true;
}

@Override
public int hashCode() {
return new Long(getFeatureId()).hashCode();
}

I overcame this problem by returning some random number if the featureId is null

@Override
public int hashCode() {

if(ValidationUtil.isNull(getFeatureId())) {
//return random number

}
return new Long(getFeatureId()).hashCode();
}

Is this the best practice to be followed or hibernate has any other way to overcome this problem. Please do suggest


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 1:08 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
Vinu wrote:
I overcame this problem by returning some random number if the featureId is null

You should never return a random number for the hashCode. Coz semantics of hashCode also says that:
Quote:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

So using random number will go against this rule. I think the solution would be to use the un-saved id value to generate the hashCode in this case. Which means in the mapping you have specified:
Quote:
<id name="featureId" column="F_ID" type="java.lang.Integer" unsaved-value="0">
<generator class=".....">......</generator>
</id>

Then use 0 for generating hashCode if the object is unsaved. Like:
Code:
public int hashCode() {
   if(getFeautreId() != null)
      return new Long(getFeatureId()).hashCode();
   else
      return new (Long(0)).hashCode();
}


But Vinu, I am having a doubt here. Your ServiceModelVO to FeatureModelVO relation is MTO. So how come the result will contain non-unique members? Coz one FeatureModelVO would be related to one ServiceModelVO only once !!

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 1:28 am 
Beginner
Beginner

Joined: Tue Mar 10, 2009 11:50 pm
Posts: 23
Hi littypreethkr,

Thanks for the reply.

The relation b/w ServiceModelVO and FeatureModelVO is OTM, service model containing many features.

Are you aware of how to specify unsaved-value property in annotations. I checked the forums, they claim its not supported in Hibernate 3 annotations

Refer
http://opensource.atlassian.com/project ... se/ANN-609


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 1:50 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
Well I dont have any idea how to specify un-saved value in annotation. The ticket also says that its unsupported. But if you know that a particular value say "0" or "-1" is not going to be used as id value then you can use that number for generating hashCode for un-saved records. No need to specify it in the mapping.

Quote:
The relation b/w ServiceModelVO and FeatureModelVO is OTM, service model containing many features.

Okk fine. Service model has many features, but those features will be unique. If you have non-unique FMVOs in a SMVO then that means that SMVO is related to same FMVO more than once. How can that happen? Coz its a MTO or OTM relation. So I assume that the FM table has a foreign-key refering to SM. So if SM1 is related to FM1 once then it cannot be related to FM1 again.

I hope now you got my point.

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 3:36 am 
Beginner
Beginner

Joined: Tue Mar 10, 2009 11:50 pm
Posts: 23
Hi littypreethkr, thanks for the reply

Yes, FM (FeatureModel) table has a foreign-key refering to SM (ServiceModel)

The FM in turn has one-to-many with AttributeModel (AM), feature having many attributes. The duplicate FM's are happening only for those which contain more than one AM's. Viz only those features which contain more than one attribute are getting duplicated in features Collection set of servicemodel.


I will try this

return new (Long(0)).hashCode(); in my FeatureModel hashcode method for un-saved objects, but wouldn't be same as returning same hashcode value for mulitple un-saved objects, wherein hibernate will not add more than one FM in the SM set during fresh insert.[/quote]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 4:00 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
Vinu wrote:
but wouldn't be same as returning same hashcode value for mulitple un-saved objects

Yes... So for all unsaved objects your hashCode is same. But that wont be any issue. Coz as I said earlier, hashCode equality doesnt mean object (or object value) equality where as object (or object value) equality should mean that hashCode are also equal.

With this implementation of hashCode and equals method, your Set should now have unique objects only.

_________________
Regards,
Litty Preeth


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 4:58 am 
Beginner
Beginner

Joined: Tue Mar 10, 2009 11:50 pm
Posts: 23
Hi littypreethkr,

Thanks for the reply.

I have an issue with one more issue posted here.

http://forum.hibernate.org/viewtopic.ph ... highlight=

Great if you can provide any insights

I need to achieve unidirectional one-to-many from primary key of one class to composite primary key of other. Please let me know how to do the same in hibernate


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 12, 2009 5:06 am 
Expert
Expert

Joined: Fri Jan 30, 2009 1:47 am
Posts: 292
Location: Bangalore, India
Ratings are welcome... if any posts helped you.... ;-)

I will look at that one also.

_________________
Regards,
Litty Preeth


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