views:

27

answers:

3

Hi

An entity X has a list of entity Y and the entity Y has an instance of entity Z.

The relation between X to Y is OneToMany and the relation between Y to Z is ManyToOne.

I want to retrieve X and have all the associated entities retrieved with them as well.

What HQL query do I write so that I get the whole chain retrieved all at once. At present its hibernateTemplate.find("from X"). or What annonations do I use for it?

X=ServiceProvider, Y=BusinessLocations.java, Z=State.java

I have the entities annotated below and I am having the whole chain persisted into database but when i try to retrieve the list of Y(BusinessLocation), I get

nothing.

What do I do join X with Y and Y with Z?

Below are the entities x, Y and Z.

ServiceProvider.java

@Entity
public class ServiceProvider implements Serializable{

    private Long id;    
    private Set<BusinessLocation> businessLocations = new HashSet<BusinessLocation>();

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    @OneToMany(mappedBy="serviceProvider", targetEntity=BusinessLocation.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    public Set<BusinessLocation> getBusinessLocations() {
        return businessLocations;
    }

    public void setBusinessLocations(Set<BusinessLocation> businessLocations) {
        this.businessLocations = businessLocations;
    }

    public boolean equals(Object obj) {
        if(!(obj instanceof ServiceProvider)) return false;
        ServiceProvider other = (ServiceProvider) obj;
        return new EqualsBuilder().append(businessLocations, other.businessLocations).isEquals();
    }
}

BusinessLocation.java

@Entity
public class BusinessLocation implements Serializable{

    private Long id;
    private String address;
    private String city;
    private State state;
    private String pincode;
    private ServiceProvider serviceProvider;

    public BusinessLocation() {     
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="state_id")
    public State getState() {
        return state;
    }
    public void setState(State state) {
        this.state = state;
    }   
    public void setPincode(String pincode) {
        this.pincode = pincode;
    }

    public String getPincode() {
        return pincode;
    }

    @ManyToOne
    @JoinColumn(name="serviceProvider_id")
    public ServiceProvider getServiceProvider() {
        return serviceProvider;
    }
    public void setServiceProvider(ServiceProvider serviceProvider) {
        this.serviceProvider = serviceProvider;
    }

    public boolean equals(Object obj) {
        if( !(obj instanceof BusinessLocation)) return false;
        BusinessLocation other = (BusinessLocation) obj;        
        return new EqualsBuilder().append(address, other.address).append(city, other.city).append(state, other.state).append(pincode, 

other.pincode).append(serviceProvider, other.serviceProvider).isEquals();
    }

    public int hashCode() {
        return new HashCodeBuilder().append(address).append(city).append(state).append(pincode).append(serviceProvider).toHashCode();
    }
}

State.java

@Entity
public class State implements Serializable {

    private Long id;
    private String abbreviatedName;
    private String name;
    private List<BusinessLocation> businessLocations;

    @Id
    @GeneratedValue 
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getAbbreviatedName() {
        return abbreviatedName;
    }
    public void setAbbreviatedName(String abbreviatedName) {
        this.abbreviatedName = abbreviatedName;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }


    @OneToMany(mappedBy="state", targetEntity=BusinessLocation.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    public List<BusinessLocation> getBusinessLocations() {
        return businessLocations;
    }
    public void setBusinessLocations(List<BusinessLocation> businessLocations) {
        this.businessLocations = businessLocations;
    }

    public boolean equals(Object obj) {
        if(! (obj instanceof State)) return false;
        State other = (State) obj;
        return new EqualsBuilder().append(abbreviatedName, other.abbreviatedName).append(name, other.name).append(businessLocations, 

other.businessLocations).isEquals();
    }

    public int hashCode() {
        return new HashCodeBuilder().append(name).append(abbreviatedName).append(businessLocations).toHashCode();
    }

}

Could someone help me out here?

Thanks

A: 

What about:

Query q - entityManager.createQuery("Select x from ServiceProvider x inner join x.businessLocations as y and inner join y.state as z where x.id = ?1");
Thierry-Dimitri Roy
A: 

I have the entities annotated below and I am having the whole chain persisted into database but when i try to retrieve the list of Y (BusinessLocation), I get... nothing

You should activate SQL logging to see what is happening and check the data because the annotation part looks correct:

  • the one-to-many between ServiceProvider and BusinessLocation is EAGER
  • the many-to-one between BusinessLocation and State is EAGER (by default)

So the whole chain should be retrieved eagerly. If this is not what is happening, you might want to check the data and the SQL, hence the suggestion.

As an alternative to EAGER associations, you could use a FETCH JOIN to prefetch the related data:

FROM ServiceProvider provider
  INNER JOIN FETCH provider.businessLocations location
  LEFT JOIN FETCH location.state

But note that JPA 1.0 does not allow nested join fetches in JPQL, this is Hibernate specific.

References

  • Hibernate Core Reference Guide
  • JPA 1.0 specification
    • Section 9.1.22 "ManyToOne Annotation"
    • Section 4.4.5.3 "Fetch Joins"
Pascal Thivent
A: 

Hello Pascal and Roy

Its just that I wasnt getting any errors but nothing more than the ServiceProvider I had in my database. But When I try

FROM ServiceProvider provider
  INNER JOIN FETCH provider.businessLocations location
  LEFT JOIN FETCH location.state

or

FROM ServiceProvider provider
  INNER JOIN FETCH provider.businessLocations location
  INNER JOIN FETCH location.state

I get the following error:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.RangeCheck(ArrayList.java:547)
    at java.util.ArrayList.get(ArrayList.java:322)
    at com.inception.web.RegisterServiceProviderController.formBackingObject(RegisterServiceProviderController.java:31)
    at org.springframework.web.servlet.mvc.AbstractFormController.getErrorsForNewForm(AbstractFormController.java:358)
    at org.springframework.web.servlet.mvc.AbstractFormController.showNewForm(AbstractFormController.java:338)
    at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:278)
    at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:476)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:431)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
    at java.lang.Thread.run(Thread.java:619)

What am I missing?

Thanks

skip
I do have an entry for ServiceProvider in my database, I wonder why is it saying that I have a size 0 in when I m trying to get just the first ServiceProvider out of the list being returned by the hibernateTemplate.find(..) method when I tried the query being sent to me?
skip