I have two classes TEAM and PERSON. Each team has a "leader" (association to PERSON) and may have various "members" (set with many-to-many relation to PERSON).
I am trying to find the "correct" way (using Criteria) to formulate a finder like "all the teams where a certain person is either the leader or a member", which translates to "all the teams where ((leader EQ person) OR (set members CONTAINS person))".
Now I am having problems choosing the "best" method for this "set contains"-Restriction.
Below I have used "createAlias" and a restriction of "ms.id eq person.getId()". This results in an INNER JOIN from TEAM to TEAM_PERSON and an INNER JOIN from TEAM_PERSON to PERSON.
There are two "problems" with this.
1. It's using an INNER JOIN instead of a LEFT OUTER JOIN. Which means teams without any member will never be selected, even when the leader matches.
2. The second INNER JOIN from TEAM_PERSON to PERSON is unnecessary. Since I am only interessed in the existence of a matching person in the members set, only the ID of the PERSON is relevant. And this ID is already in the TEAM_PERSON table. The second join is only adding a performance hit (albeit a small one) and should be avoided.
I have read in various postings here, that the first problem can't be avoided with the Criteria API and it seems like I have to live with that.
But I wonder wether there is a solution to the second problem?
Is there an "easier" way to formulate the "set contains" restriction?
Any help would be appreciated.
Stefan
Hibernate version:
3.0.5
Mapping documents:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibertest.bo">
<class name="Person" table="PERSON">
<id name="id">
<generator class="native"/>
</id>
<property name="name" not-null="true"/>
</class>
<class name="Team" table="TEAM">
<id name="id">
<generator class="native"/>
</id>
<property name="name" not-null="true"/>
<many-to-one
name="leader"
class="hibertest.bo.Person"
cascade="none"
outer-join="auto"
update="true"
insert="true"
column="LEADER"
not-null="false"
/>
<set
name="members"
table="TEAM_PERSON"
lazy="true"
cascade="none"
sort="unsorted">
<key column="TEAM_ID"/>
<many-to-many
class="hibertest.bo.Person"
column="PERSON_ID"
outer-join="auto"/>
</set>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
Criteria crit = session.createCriteria(Team.class);
SimpleExpression exprLeader = Restrictions.eq("leader", person);
crit.createAlias("members", "ms");
SimpleExpression exprMembers = Restrictions.eq("ms.id", person.getId());
crit.add(Restrictions.disjunction().add(exprLeader).add(exprMembers));
crit.list();
Name and version of the database you are using:Oracle 10.1.0.4
The generated SQL (show_sql=true):Code:
select this_.id as id1_, this_.name as name1_1_, this_.LEADER as LEADER1_1_, members3_.TEAM_ID as TEAM1_, ms1_.id as PERSON2_, ms1_.id as id0_, ms1_.name as name0_0_ from TEAM this_ inner join TEAM_PERSON members3_ on this_.id=members3_.TEAM_ID inner join PERSON ms1_ on members3_.PERSON_ID=ms1_.id where (this_.LEADER=? or ms1_.id=?)