forked from nhibernate/nhibernate-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPersistentArrayHolder.cs
314 lines (271 loc) · 7.67 KB
/
PersistentArrayHolder.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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using NHibernate.DebugHelpers;
using NHibernate.Engine;
using NHibernate.Loader;
using NHibernate.Persister.Collection;
using NHibernate.Type;
namespace NHibernate.Collection
{
/// <summary>
/// A persistent wrapper for an array. lazy initialization is NOT supported
/// </summary>
/// <remarks> Use of Hibernate arrays is not really recommended. </remarks>
[Serializable]
[DebuggerTypeProxy(typeof (CollectionProxy))]
public partial class PersistentArrayHolder : AbstractPersistentCollection, ICollection
{
private static readonly INHibernateLogger log = NHibernateLogger.For(typeof (PersistentArrayHolder));
private Array array;
[NonSerialized] private readonly System.Type elementClass;
/// <summary>
/// A temporary list that holds the objects while the PersistentArrayHolder is being
/// populated from the database.
/// </summary>
[NonSerialized] private List<object> tempList;
public PersistentArrayHolder(ISessionImplementor session, object array) : base(session)
{
this.array = (Array) array;
SetInitialized();
}
public PersistentArrayHolder(ISessionImplementor session, ICollectionPersister persister) : base(session)
{
elementClass = persister.ElementClass;
}
/// <summary>
/// Gets or sets the array.
/// </summary>
/// <value>The array.</value>
public object Array
{
get { return array; }
protected set
{
array = (Array)value;
}
}
/// <summary>
/// Returns the user-visible portion of the NHibernate PersistentArrayHolder.
/// </summary>
/// <returns>
/// The array that contains the data, not the NHibernate wrapper.
/// </returns>
public override object GetValue()
{
return array;
}
public override object GetSnapshot(ICollectionPersister persister)
{
int length = array.Length;
Array result = System.Array.CreateInstance(persister.ElementClass, length);
for (int i = 0; i < length; i++)
{
object elt = array.GetValue(i);
try
{
result.SetValue(persister.ElementType.DeepCopy(elt, persister.Factory), i);
}
catch (Exception e)
{
log.Error(e, "Array element type error");
throw new HibernateException("Array element type error", e);
}
}
return result;
}
public override bool IsSnapshotEmpty(object snapshot)
{
return ((Array) snapshot).Length == 0;
}
public override ICollection GetOrphans(object snapshot, string entityName)
{
return GetOrphans((object[]) snapshot, (object[]) array, entityName, Session);
}
public override bool IsWrapper(object collection)
{
return array == collection;
}
public override bool EqualsSnapshot(ICollectionPersister persister)
{
IType elementType = persister.ElementType;
Array snapshot = (Array) GetSnapshot();
int xlen = snapshot.Length;
if (xlen != array.Length)
{
return false;
}
for (int i = 0; i < xlen; i++)
{
if (elementType.IsDirty(snapshot.GetValue(i), array.GetValue(i), Session))
{
return false;
}
}
return true;
}
public ICollection Elements()
{
// NH Different implementation but same result
return (ICollection) array.Clone();
}
public override bool Empty
{
get { return false; }
}
public override object ReadFrom(DbDataReader rs, ICollectionPersister role, ICollectionAliases descriptor, object owner)
{
object element = role.ReadElement(rs, owner, descriptor.SuffixedElementAliases, Session);
int index = (int) role.ReadIndex(rs, descriptor.SuffixedIndexAliases, Session);
for (int i = tempList.Count; i <= index; i++)
{
tempList.Add(null);
}
tempList[index] = element;
return element;
}
public override IEnumerable Entries(ICollectionPersister persister)
{
return Elements();
}
/// <summary>
/// Before <see cref="ReadFrom" /> is called the PersistentArrayHolder needs to setup
/// a temporary list to hold the objects.
/// </summary>
public override void BeginRead()
{
base.BeginRead();
tempList = new List<object>();
}
/// <summary>
/// Takes the contents stored in the temporary list created during <see cref="BeginRead" />
/// that was populated during <see cref="ReadFrom" /> and write it to the underlying
/// array.
/// </summary>
public override bool EndRead(ICollectionPersister persister)
{
SetInitialized();
array = System.Array.CreateInstance(elementClass, tempList.Count);
for (int i = 0; i < tempList.Count; i++)
{
array.SetValue(tempList[i], i);
}
tempList = null;
return true;
}
public override void BeforeInitialize(ICollectionPersister persister, int anticipatedSize) {}
public override bool IsDirectlyAccessible
{
get { return true; }
}
/// <summary>
/// Initializes this array holder from the cached values.
/// </summary>
/// <param name="persister">The CollectionPersister to use to reassemble the Array.</param>
/// <param name="disassembled">The disassembled Array.</param>
/// <param name="owner">The owner object.</param>
public override void InitializeFromCache(ICollectionPersister persister, object disassembled, object owner)
{
object[] cached = (object[]) disassembled;
array = System.Array.CreateInstance(persister.ElementClass, cached.Length);
for (int i = 0; i < cached.Length; i++)
{
array.SetValue(persister.ElementType.Assemble(cached[i], Session, owner), i);
}
}
public override object Disassemble(ICollectionPersister persister)
{
int length = array.Length;
object[] result = new object[length];
for (int i = 0; i < length; i++)
{
result[i] = persister.ElementType.Disassemble(array.GetValue(i), Session, null);
}
return result;
}
public override IEnumerable GetDeletes(ICollectionPersister persister, bool indexIsFormula)
{
IList deletes = new List<object>();
Array sn = (Array) GetSnapshot();
int snSize = sn.Length;
int arraySize = array.Length;
int end;
if (snSize > arraySize)
{
for (int i = arraySize; i < snSize; i++)
{
deletes.Add(i);
}
end = arraySize;
}
else
{
end = snSize;
}
for (int i = 0; i < end; i++)
{
if (array.GetValue(i) == null && sn.GetValue(i) != null)
{
deletes.Add(i);
}
}
return deletes;
}
public override bool NeedsInserting(object entry, int i, IType elemType)
{
Array sn = (Array) GetSnapshot();
return array.GetValue(i) != null && (i >= sn.Length || sn.GetValue(i) == null);
}
public override bool NeedsUpdating(object entry, int i, IType elemType)
{
Array sn = (Array) GetSnapshot();
return
i < sn.Length && sn.GetValue(i) != null && array.GetValue(i) != null
&& elemType.IsDirty(array.GetValue(i), sn.GetValue(i), Session);
}
public override object GetIndex(object entry, int i, ICollectionPersister persister)
{
return i;
}
public override object GetElement(object entry)
{
return entry;
}
public override object GetSnapshotElement(object entry, int i)
{
Array sn = (Array) GetSnapshot();
return sn.GetValue(i);
}
public override bool EntryExists(object entry, int i)
{
return entry != null;
}
#region ICollection Members
// NH Different : we implement one of the "minimal" interface the NET Array support
void ICollection.CopyTo(Array array, int index)
{
this.array.CopyTo(array, index);
}
int ICollection.Count
{
get { return array.Length; }
}
object ICollection.SyncRoot
{
get { return this; }
}
bool ICollection.IsSynchronized
{
get { return false; }
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return array.GetEnumerator();
}
#endregion
}
}