forked from nhibernate/nhibernate-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEntityProjection.cs
214 lines (173 loc) · 6.04 KB
/
EntityProjection.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
using System;
using System.Collections.Generic;
using NHibernate.Engine;
using NHibernate.Loader;
using NHibernate.Loader.Criteria;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Type;
using IQueryable = NHibernate.Persister.Entity.IQueryable;
namespace NHibernate.Criterion
{
/// <summary>
/// Entity projection
/// </summary>
[Serializable]
public class EntityProjection : IProjection
{
private string _entityAlias;
private System.Type _entityType;
private IType[] _types;
private string[] _identifierColumnAliases;
/// <summary>
/// Root entity projection
/// </summary>
public EntityProjection() : this(null, null)
{
}
/// <summary>
/// Entity projection for given type and alias
/// </summary>
/// <param name="entityType">Type of entity</param>
/// <param name="entityAlias">Entity alias</param>
public EntityProjection(System.Type entityType, string entityAlias)
{
_entityType = entityType;
_entityAlias = entityAlias;
}
/// <summary>
/// Fetch all lazy properties
/// </summary>
public bool FetchLazyProperties { get; set; }
/// <summary>
/// Fetch individual lazy properties or property groups
/// Note: To fetch single property it must be mapped with unique fetch group (lazy-group)
/// </summary>
public ICollection<string> FetchLazyPropertyGroups { get; set; }
/// <summary>
/// Lazy load entity
/// </summary>
public bool Lazy { get; set; }
internal IQueryable Persister { get; private set; }
internal string ColumnAliasSuffix { get; private set; }
internal string TableAlias { get; private set; }
#region Configuration methods
/// <summary>
/// Lazy load entity
/// </summary>
public EntityProjection SetLazy(bool lazy = true)
{
Lazy = lazy;
return this;
}
/// <summary>
/// Fetch all lazy properties
/// </summary>
public EntityProjection SetFetchLazyProperties(bool fetchLazyProperties = true)
{
FetchLazyProperties = fetchLazyProperties;
return this;
}
/// <summary>
/// Fetch individual lazy properties or property groups
/// Provide lazy property name and it will be fetched along with properties that belong to the same fetch group (lazy-group)
/// Note: To fetch single property it must be mapped with unique fetch group (lazy-group)
/// </summary>
public EntityProjection SetFetchLazyPropertyGroups(params string[] lazyPropertyGroups)
{
FetchLazyPropertyGroups = lazyPropertyGroups;
return this;
}
#endregion Configuration methods
#region IProjection implementation
string[] IProjection.Aliases => new[] { _entityAlias };
bool IProjection.IsAggregate => false;
bool IProjection.IsGrouped => false;
IType[] IProjection.GetTypes(string alias, ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return null;
}
string[] IProjection.GetColumnAliases(string alias, int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return null;
}
IType[] IProjection.GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
SetFields(criteriaQuery);
return _types;
}
string[] IProjection.GetColumnAliases(int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
{
SetFields(criteriaQuery);
return _identifierColumnAliases;
}
SqlString IProjection.ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery)
{
SetFields(criteriaQuery);
var identifierSelectFragment = Persister.GetIdentifierSelectFragment(TableAlias, ColumnAliasSuffix)
.ToSqlStringFragment(false);
return new SqlString(
Lazy
? identifierSelectFragment
: string.Concat(
identifierSelectFragment,
GetPropertySelectFragment().ToSqlStringFragment()));
}
private SelectFragment GetPropertySelectFragment()
{
return FetchLazyProperties
? Persister.GetPropertiesSelectFragment(TableAlias, ColumnAliasSuffix, FetchLazyProperties)
: Persister.GetPropertiesSelectFragment(TableAlias, ColumnAliasSuffix, FetchLazyPropertyGroups);
}
SqlString IProjection.ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
throw new InvalidOperationException("not a grouping projection");
}
TypedValue[] IProjection.GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return Array.Empty<TypedValue>();
}
#endregion IProjection implementation
private void SetFields(ICriteriaQuery criteriaQuery)
{
//Persister is required, so let's use it as "initialized marker"
if (Persister != null)
return;
if (!(criteriaQuery is ISupportEntityProjectionCriteriaQuery entityProjectionQuery))
{
throw new ArgumentException(
$"Projecting to entities requires a '{criteriaQuery.GetType().FullName}' type to implement " +
$"{nameof(ISupportEntityProjectionCriteriaQuery)} interface.",
nameof(criteriaQuery));
}
var criteria = entityProjectionQuery.RootCriteria;
if (!Lazy)
{
entityProjectionQuery.RegisterEntityProjection(this);
}
if (_entityAlias == null)
{
_entityAlias = criteria.Alias;
}
ICriteria subcriteria =
criteria.GetCriteriaByAlias(_entityAlias)
?? throw new HibernateException($"Criteria\\QueryOver alias '{_entityAlias}' for entity projection is not found.");
var entityName =
criteriaQuery.GetEntityName(subcriteria)
?? throw new HibernateException($"Criteria\\QueryOver alias '{_entityAlias}' is not associated with an entity.");
Persister =
criteriaQuery.Factory.GetEntityPersister(entityName) as IQueryable
?? throw new HibernateException($"Projecting to entities requires a '{typeof(IQueryable).FullName}' persister, '{entityName}' does not have one.");
if (_entityType == null)
{
_entityType = Persister.Type.ReturnedClass;
}
TableAlias = criteriaQuery.GetSQLAlias(
subcriteria,
Persister.IdentifierPropertyName ?? string.Empty);
ColumnAliasSuffix = BasicLoader.GenerateSuffix(criteriaQuery.GetIndexForAlias());
_identifierColumnAliases = Persister.GetIdentifierAliases(ColumnAliasSuffix);
_types = new IType[] { TypeFactory.ManyToOne(Persister.EntityName, true) };
}
}
}