2
* Hibernate, Relational Persistence for Idiomatic Java
4
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5
* indicated by the @author tags or express copyright attribution
6
* statements applied by the authors. All third-party contributions are
7
* distributed under license by Red Hat Middleware LLC.
9
* This copyrighted material is made available to anyone wishing to use, modify,
10
* copy, or redistribute it subject to the terms and conditions of the GNU
11
* Lesser General Public License, as published by the Free Software Foundation.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with this distribution; if not, write to:
20
* Free Software Foundation, Inc.
21
* 51 Franklin Street, Fifth Floor
22
* Boston, MA 02110-1301 USA
25
package org.hibernate.loader.collection;
27
import java.util.ArrayList;
28
import java.util.Iterator;
29
import java.util.List;
33
import org.hibernate.FetchMode;
34
import org.hibernate.LockMode;
35
import org.hibernate.MappingException;
36
import org.hibernate.engine.SessionFactoryImplementor;
37
import org.hibernate.loader.BasicLoader;
38
import org.hibernate.loader.OuterJoinableAssociation;
39
import org.hibernate.persister.collection.QueryableCollection;
40
import org.hibernate.sql.JoinFragment;
41
import org.hibernate.sql.Select;
42
import org.hibernate.type.AssociationType;
43
import org.hibernate.util.CollectionHelper;
44
import org.hibernate.util.StringHelper;
47
* Walker for collections of values and many-to-many associations
49
* @see BasicCollectionLoader
52
public class BasicCollectionJoinWalker extends CollectionJoinWalker {
54
private final QueryableCollection collectionPersister;
56
public BasicCollectionJoinWalker(
57
QueryableCollection collectionPersister,
60
SessionFactoryImplementor factory,
62
throws MappingException {
64
super(factory, enabledFilters);
66
this.collectionPersister = collectionPersister;
68
String alias = generateRootAlias( collectionPersister.getRole() );
70
walkCollectionTree(collectionPersister, alias);
72
List allAssociations = new ArrayList();
73
allAssociations.addAll(associations);
74
allAssociations.add( new OuterJoinableAssociation(
75
collectionPersister.getCollectionType(),
79
JoinFragment.LEFT_OUTER_JOIN,
81
CollectionHelper.EMPTY_MAP
84
initPersisters(allAssociations, LockMode.NONE);
85
initStatementString(alias, batchSize, subquery);
89
private void initStatementString(
92
final String subquery)
93
throws MappingException {
95
final int joins = countEntityPersisters( associations );
96
final int collectionJoins = countCollectionPersisters( associations ) + 1;
98
suffixes = BasicLoader.generateSuffixes( joins );
99
collectionSuffixes = BasicLoader.generateSuffixes( joins, collectionJoins );
101
StringBuffer whereString = whereString(
103
collectionPersister.getKeyColumnNames(),
108
String manyToManyOrderBy = "";
109
String filter = collectionPersister.filterFragment( alias, getEnabledFilters() );
110
if ( collectionPersister.isManyToMany() ) {
111
// from the collection of associations, locate OJA for the
112
// ManyToOne corresponding to this persister to fully
113
// define the many-to-many; we need that OJA so that we can
114
// use its alias here
115
// TODO : is there a better way here?
116
Iterator itr = associations.iterator();
117
AssociationType associationType = ( AssociationType ) collectionPersister.getElementType();
118
while ( itr.hasNext() ) {
119
OuterJoinableAssociation oja = ( OuterJoinableAssociation ) itr.next();
120
if ( oja.getJoinableType() == associationType ) {
122
filter += collectionPersister.getManyToManyFilterFragment(
126
manyToManyOrderBy += collectionPersister.getManyToManyOrderByString( oja.getRHSAlias() );
130
whereString.insert( 0, StringHelper.moveAndToBeginning( filter ) );
132
JoinFragment ojf = mergeOuterJoins(associations);
133
Select select = new Select( getDialect() )
135
collectionPersister.selectFragment(alias, collectionSuffixes[0] ) +
136
selectString(associations)
138
.setFromClause( collectionPersister.getTableName(), alias )
139
.setWhereClause( whereString.toString() )
141
ojf.toFromFragmentString(),
142
ojf.toWhereFragmentString()
145
select.setOrderByClause( orderBy( associations, mergeOrderings( collectionPersister.getSQLOrderByString(alias), manyToManyOrderBy ) ) );
147
if ( getFactory().getSettings().isCommentsEnabled() ) {
148
select.setComment( "load collection " + collectionPersister.getRole() );
151
sql = select.toStatementString();
155
* We can use an inner join for first many-to-many association
157
protected int getJoinType(
158
AssociationType type,
161
Set visitedAssociations,
166
throws MappingException {
168
int joinType = super.getJoinType(
178
//we can use an inner join for the many-to-many
179
if ( joinType==JoinFragment.LEFT_OUTER_JOIN && "".equals(path) ) {
180
joinType=JoinFragment.INNER_JOIN;
185
public String toString() {
186
return getClass().getName() + '(' + collectionPersister.getRole() + ')';