forked from nhibernate/nhibernate-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCollectionLoader.cs
129 lines (111 loc) · 3.63 KB
/
CollectionLoader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections;
using NHibernate.Collection;
using NHibernate.Engine;
using NHibernate.Persister.Collection;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;
namespace NHibernate.Loader.Collection
{
/// <summary>
/// Loads a collection of values or a many-to-many association
/// </summary>
/// <remarks>
/// The collection persister must implement <see cref="IQueryableCollection" />. For
/// other collections, create a customized subclass of <see cref="Loader" />.
/// <seealso cref="OneToManyLoader" />
/// </remarks>
public class CollectionLoader : OuterJoinLoader, ICollectionInitializer
{
private readonly IQueryableCollection collectionPersister;
private readonly IType keyType;
public CollectionLoader( IQueryableCollection persister, ISessionFactoryImplementor factory )
: this( persister, 1, factory )
{
}
public CollectionLoader( IQueryableCollection persister, int batchSize, ISessionFactoryImplementor factory )
: base( factory.Dialect )
{
this.collectionPersister = persister;
this.keyType = persister.KeyType;
string alias = GenerateRootAlias( persister.Role );
IList associations = WalkCollectionTree( persister, alias, factory );
InitStatementString( persister, alias, associations, batchSize, factory );
InitClassPersisters( associations );
PostInstantiate();
}
private void InitClassPersisters( IList associations )
{
int joins = associations.Count;
lockModeArray = CreateLockModeArray( joins, LockMode.None );
classPersisters = new ILoadable[joins];
Owners = new int[joins];
int i = 0;
foreach( OuterJoinableAssociation oj in associations )
{
classPersisters[ i ] = ( ILoadable ) oj.Joinable;
Owners[ i ] = ToOwner( oj, joins, oj.IsOneToOne );
i++;
}
if( ArrayHelper.IsAllNegative( Owners ) )
{
Owners = null;
}
}
protected override ICollectionPersister CollectionPersister
{
get { return collectionPersister; }
}
public void Initialize( object id, ISessionImplementor session )
{
LoadCollection( session, id, keyType );
}
private void InitStatementString( IQueryableCollection persister, string alias, IList associations, int batchSize, ISessionFactoryImplementor factory )
{
Suffixes = GenerateSuffixes( associations.Count );
SqlStringBuilder whereString = WhereString( factory, alias, persister.KeyColumnNames, persister.KeyType, batchSize );
if( persister.HasWhere )
{
whereString
.Add( " and " )
.Add( persister.GetSQLWhereString( alias ) );
}
JoinFragment ojf = MergeOuterJoins( associations );
SqlSelectBuilder select = new SqlSelectBuilder( factory )
.SetSelectClause(
persister.SelectFragment( alias ).Append(
SelectString( associations, factory ) ).ToString()
)
.SetFromClause( persister.TableName, alias )
.SetWhereClause( whereString.ToSqlString() )
.SetOuterJoins(
ojf.ToFromFragmentString,
ojf.ToWhereFragmentString
);
if( persister.HasOrdering )
{
select.SetOrderByClause( persister.GetSQLOrderByString( alias ) );
}
SqlString = select.ToSqlString();
}
protected override JoinType GetJoinType(
IAssociationType type,
FetchMode fetchMode,
string path,
string table,
string[ ] foreignKeyColumns,
ISessionFactoryImplementor factory
)
{
JoinType joinType = base.GetJoinType( type, fetchMode, path, table, foreignKeyColumns, factory );
// We can use an inner-join for the many-to-many
if( joinType == JoinType.LeftOuterJoin && string.Empty.Equals( path ) )
{
joinType = JoinType.InnerJoin;
}
return joinType;
}
}
}