Search code examples
javahibernatehibernate-criteria

How to add Restrictions to OneToMany mapping in hibernate


I was stuck with getting result with @OneToMany mapping. Here are the model classes.

Assessment.java

    @Entity
    @FilterDef(name = "tenantFilter", parameters = @ParamDef(name = "tenantIdParam", type = "string"))
    @Filters(@Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
    @Table(name = "assessment")
    public class Assessment extends Revenue implements Comparable<Assessment> {

    //other attriutes

    @ManyToOne(fetch = FetchType.LAZY)
        @Cascade(value = CascadeType.ALL)
        @JoinColumn(name = "property_id")
        private Property propertyAssessment;
    @Column(name = "tenant_id", nullable = false)
        private String tenantId;

//getters and setters
    }

Property.java

@Entity
@FilterDef(name = "tenantFilter", parameters = @ParamDef(name = "tenantIdParam", type = "string"))
@Filters(@Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
@Table(name = "property")
public class Property implements java.io.Serializable {

//other attributes

@ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mas_gnd_id")
    private GramaNiladhariDivision gramaNiladhariDivision;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mas_so_id", nullable = true)
    private SubOffice subOffice;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mas_ward_id", nullable = true)
    private Ward ward;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mas_road_id", nullable = true)
    private Road road;
    @Column(name = "side_of_property")
    private Character sideOfProperty;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mas_pt_id", nullable = true)
    private PropertyType propertyType;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "property_description")
    private PropertyDescription propertyDescription;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "propertyAssessment")
    @Cascade(value = CascadeType.ALL)
    private List<Assessment> assessments = new ArrayList<Assessment>(0);
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "property")
    @Cascade(value = CascadeType.ALL)
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<PropertyOwner> propertyOwners = new ArrayList<PropertyOwner>(0);

//getters and setters
}

PropertyOwner.java

@Entity
@FilterDef(name = "tenantFilter", parameters = @ParamDef(name = "tenantIdParam", type = "string"))
@Filters(@Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
@Table(name = "property_owner")
public class PropertyOwner implements java.io.Serializable {

//other attributes

@OneToOne(fetch = FetchType.EAGER)
    @Cascade(value = CascadeType.ALL)
    @JoinColumn(name = "person_id")
    private Person person;
    @Column(name = "is_main")
    private Boolean main;
    @ManyToOne(fetch = FetchType.LAZY)
    @Cascade(value = CascadeType.ALL)
    @JoinColumn(name = "property_id")
    private Property property = new Property();
    @Column(name = "tenant_id", nullable = false, updatable = false)
    private String tenantId;
    @Column(name = "status", columnDefinition = "varchar(255) default 'active'")
    private String status;

//getters and setters

}

So my question is I want to load PropertyOwners where status is INACTIVE. I tried to write Criteria in different ways but I couldn't get the exact result. It is always return me all the PropertyOwners regardless of their status even though I add Restriction to the status. Here is one of the Criteria which I tried.

public Assessment getAssessmentById(Long assessmentId, Object tenantId) throws HibernateException {
        Session session = getSession(tenantId);
        Assessment result;
        result = (Assessment) session
                .createCriteria(Assessment.class)
                .setFetchMode("propertyAssessment", FetchMode.JOIN)
                .createAlias("propertyAssessment.propertyOwners", "propertyOwners", JoinType.INNER_JOIN,
                        Restrictions.ne("propertyOwners.status", ScandiumKeyBox.INACTIVE))
                .setFetchMode("propertyAssessment.subOffice", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.ward", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.gramaNiladhariDivision", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.propertyDescription", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.propertyType", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.road", FetchMode.JOIN).setFetchMode("registerNumber", FetchMode.JOIN)
                .setFetchMode("registerPageNumbers", FetchMode.JOIN).setFetchMode("elgActivity", FetchMode.JOIN)
                .add(Restrictions.eq("id", assessmentId)).uniqueResult();
        return result;
    }

Please provide me a proper solution for this problem. Thank you.


Solution

  • Finally I found a way to get exact result from the PropertyOwners's status. The tricky part is when retrieve the result hibernate load all the matching entity regardless of the Restrictions in createAlias because of JoinType.INNER_JOIN. So I put JoinType.LEFT_OUTER_JOIN to the createAlias and remove Restrictions in createAlias. I set the Restrictions as usual way. Now it's giving the exact result matching the status.

    Here is the modified method.

    public Assessment getAssessmentById(Long assessmentId, Object tenantId) throws HibernateException {
            Session session = getSession(tenantId);
            Assessment result;
            result = (Assessment) session
                .createCriteria(Assessment.class)
                .setFetchMode("propertyAssessment", FetchMode.JOIN)
                .createAlias("propertyAssessment.propertyOwners", "propertyOwners", JoinType.LEFT_OUTER_JOIN)
                .setFetchMode("propertyAssessment.subOffice", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.ward", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.gramaNiladhariDivision", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.propertyDescription", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.propertyType", FetchMode.JOIN)
                .setFetchMode("propertyAssessment.road", FetchMode.JOIN).setFetchMode("registerNumber", FetchMode.JOIN)
                .setFetchMode("registerPageNumbers", FetchMode.JOIN).setFetchMode("elgActivity", FetchMode.JOIN)
                .add(Restrictions.eq("id", assessmentId))
                .add(Restrictions.ne("propertyOwners.status", ScandiumKeyBox.INACTIVE))
                .uniqueResult();
            return result;
        }
    

    Thank you.