Hibernate version:hibernate-3.1
I want to use Query by Criteria for all of my queries but I cannot figure out how to do a couple of things which I believe will be doable. I have spent a considerable amount of time reading the Hibernate books/docs/forums without being able to suss the appropriate technique.
Firstly I want to be able to 'OR' two criteria where one involves an association (see scenario 1) and secondly I want to be able to 'OR' an association from derived types which have the same association names (see scenario 2).
Can anyone help?
Scenario 1)
I have a class with an association and a member:
Code:
class Class1 implements Serializable {
private Long class1Pk; // identifier
private int classState; // member
private Other1 other1; // association
}
class Other1 implements Serializable {
private Long other1Pk; // identifier
private int otherState; // member
private Set class1s; // association
}
I want to write a quey which returns the Class1 instances where the Class1 instance has a particular state OR it has an associated Other1 instance with that state.
I tried the following:
Code:
public static List findClass1sByState(final Integer state)
{
final Criteria class1Criteria = session.createCriteria(Class1.class);
class1Criteria.add(Restrictions.eq("classState", state));
final Criteria other1Criteria = class1Criteria.createCriteria("other1");
other1Criteria.add(Restrictions.eq("otherState", state));
return class1Criteria.list();
}
This runs but results in SQL like the following:
Code:
...
where
this_.class_state = ?
and other1.3_2_.other_state = ?
...
Question 1) How do I add the associated Criteria object to the original Criteria object such that it will result in a query which will 'OR' rather than 'AND' the two Criteria objects?
Scanario 2)I have a Base class with two derived classes, Derived1 and Derived2, and each of the derived classes is associated with an Other1 class.
The class' members are as follows:
Code:
class Base implements Serializable {
private Long basePk; // identifier
}
class Derived1 extends Base implements Serializable {
private Other1 other1; // association
}
class Derived2 extends Base implements Serializable {
private Other1 other1; // association
}
class Other1 implements Serializable {
private Long other1Pk; // identifier
private Set derived1s; // association
private Set derived2s; // association
}
I want to run a query to return a List of Base class instances where their derived classes are associated to an Other1 instance with a given primary key.
I tried:
Code:
public static List findBasesByOther1Pk(final Long other1PkId)
{
final Criteria baseCriteria = session.createCriteria(Base.class);
final Criterion classDerived1Criterion = Restrictions.eq("class", Derived1.class);
final Criterion other1Criterion1 = Restrictions.eq("other1.other1Pk", other1PkId);
final LogicalExpression andExprDerived1 = Restrictions.and(classDerived1Criterion, other1Criterion1);
final Criterion classDerived2Criterion = Restrictions.eq("class", Derived2.class);
final Criterion other1Criterion2 = Restrictions.eq("other1.other1Pk", other1PkId);
final LogicalExpression andExprDerived2 = Restrictions.and(classDerived2Criterion, other1Criterion2);
final LogicalExpression orExp = Restrictions.or(andExprDerived1, andExprDerived2);
baseCriteria.add(orExp);
return baseCriteria.list();
}
Which resulted in SQL like the following:
Code:
...
where
(
(
case
when base1_1_.derived1_pk_fk is not null then 1
when base1_2_.derived2_pk_fk is not null then 2
when base1_.base_pk is not null then 0
end=?
and base1_1_.other1_fk=?
)
or (
case
when base1_1_.derived1_pk_fk is not null then 1
when base1_2_.derived2_pk_fk is not null then 2
when base1_.base_pk is not null then 0
end=?
and base1_1_.other1_fk=? <<< I expected "and base1_2_.other1_fk=?"
)
)
...
This only found the Base class instances where their derived classes were Derived1 instances with the appropriate Other1 associated instances but missed the Derived2 instances.
I can fix this by changing the names of Derived1.other1 and/or Derived2.other1 so that they do not conflict (although I do not want to make this change), i.e:
Code:
class Derived1 extends Base implements Serializable {
/** persistent field */
private Other1 other1FromDerived1;
}
class Derived2 extends Base implements Serializable {
/** persistent field */
private Other1 other1FromDerived2;
}
And amending the query to:
Code:
public static List findBasesByOther1Pk(final Long other1PkId)
{
final Criteria baseCriteria = session.createCriteria(Base.class);
final Criterion other1ByDerived1Criterion = Restrictions.eq("other1FromDerived1.other1Pk", other1PkId);
final Criterion other1ByDerived2Criterion = Restrictions.eq("other1FromDerived2.other1Pk", other1PkId);
baseCriteria.add(Restrictions.or(other1ByDerived1Criterion, other1ByDerived2Criterion));
return baseCriteria.list();
}
Question 2) Is there a way of differentiating between the Derived1.other1 and Derived2.other1 without having to re-name the members? I would have expected the member names not to need to be restricted in any way.
Thanks in advance for any help are sorry if these are dumb questins - I'm new to Hibernate.