/src/NHibernate/Collection/AbstractPersistentCollection.cs

https://github.com/chester89/nhibernate-core · C# · 869 lines · 557 code · 95 blank · 217 comment · 82 complexity · e547420108ce53f25de1c4dfee47158b MD5 · raw file

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using NHibernate.Collection.Generic;
  6. using NHibernate.Engine;
  7. using NHibernate.Impl;
  8. using NHibernate.Loader;
  9. using NHibernate.Persister.Collection;
  10. using NHibernate.Type;
  11. using NHibernate.Util;
  12. namespace NHibernate.Collection
  13. {
  14. /// <summary>
  15. /// Base class for implementing <see cref="IPersistentCollection"/>.
  16. /// </summary>
  17. [Serializable]
  18. public abstract class AbstractPersistentCollection : IPersistentCollection
  19. {
  20. protected internal static readonly object Unknown = new object(); //place holder
  21. protected internal static readonly object NotFound = new object(); //place holder
  22. protected interface IDelayedOperation
  23. {
  24. object AddedInstance { get; }
  25. object Orphan { get; }
  26. void Operate();
  27. }
  28. private class AdditionEnumerable : IEnumerable
  29. {
  30. private readonly AbstractPersistentCollection enclosingInstance;
  31. public AdditionEnumerable(AbstractPersistentCollection enclosingInstance)
  32. {
  33. this.enclosingInstance = enclosingInstance;
  34. }
  35. public IEnumerator GetEnumerator()
  36. {
  37. return new AdditionEnumerator(enclosingInstance);
  38. }
  39. private class AdditionEnumerator : IEnumerator
  40. {
  41. private readonly AbstractPersistentCollection enclosingInstance;
  42. private int position = -1;
  43. public AdditionEnumerator(AbstractPersistentCollection enclosingInstance)
  44. {
  45. this.enclosingInstance = enclosingInstance;
  46. }
  47. public object Current
  48. {
  49. get
  50. {
  51. try
  52. {
  53. return enclosingInstance.operationQueue[position].AddedInstance;
  54. }
  55. catch (IndexOutOfRangeException)
  56. {
  57. throw new InvalidOperationException();
  58. }
  59. }
  60. }
  61. public bool MoveNext()
  62. {
  63. position++;
  64. return (position < enclosingInstance.operationQueue.Count);
  65. }
  66. public void Reset()
  67. {
  68. position = -1;
  69. }
  70. }
  71. }
  72. [NonSerialized] private ISessionImplementor session;
  73. private bool initialized;
  74. [NonSerialized] private List<IDelayedOperation> operationQueue;
  75. [NonSerialized] private bool directlyAccessible;
  76. [NonSerialized] private bool initializing;
  77. private object owner;
  78. private int cachedSize = -1;
  79. private string role;
  80. private object key;
  81. // collections detect changes made via their public interface and mark
  82. // themselves as dirty as a performance optimization
  83. private bool dirty;
  84. private object storedSnapshot;
  85. /// <summary>
  86. /// Not called by Hibernate, but used by non-NET serialization, eg. SOAP libraries.
  87. /// </summary>
  88. protected AbstractPersistentCollection() {}
  89. protected AbstractPersistentCollection(ISessionImplementor session)
  90. {
  91. this.session = session;
  92. }
  93. public string Role
  94. {
  95. get { return role; }
  96. }
  97. public object Key
  98. {
  99. get { return key; }
  100. }
  101. public bool IsUnreferenced
  102. {
  103. get { return role == null; }
  104. }
  105. public bool IsDirty
  106. {
  107. get { return dirty; }
  108. }
  109. public object StoredSnapshot
  110. {
  111. get { return storedSnapshot; }
  112. }
  113. protected int CachedSize
  114. {
  115. get { return cachedSize; }
  116. set { cachedSize = value; }
  117. }
  118. /// <summary>
  119. /// Is the collection currently connected to an open session?
  120. /// </summary>
  121. protected bool IsConnectedToSession
  122. {
  123. get { return session != null && session.IsOpen && session.PersistenceContext.ContainsCollection(this); }
  124. }
  125. /// <summary>
  126. /// Is this collection in a state that would allow us to "queue" additions?
  127. /// </summary>
  128. protected bool IsOperationQueueEnabled
  129. {
  130. get { return !initialized && IsConnectedToSession && IsInverseCollection; }
  131. }
  132. /// <summary> Is this collection in a state that would allow us to
  133. /// "queue" puts? This is a special case, because of orphan
  134. /// delete.
  135. /// </summary>
  136. protected bool PutQueueEnabled
  137. {
  138. get { return !initialized && IsConnectedToSession && InverseOneToManyOrNoOrphanDelete; }
  139. }
  140. /// <summary> Is this collection in a state that would allow us to
  141. /// "queue" clear? This is a special case, because of orphan
  142. /// delete.
  143. /// </summary>
  144. protected bool ClearQueueEnabled
  145. {
  146. get { return !initialized && IsConnectedToSession && InverseCollectionNoOrphanDelete; }
  147. }
  148. /// <summary> Is this the "inverse" end of a bidirectional association?</summary>
  149. protected bool IsInverseCollection
  150. {
  151. get
  152. {
  153. CollectionEntry ce = session.PersistenceContext.GetCollectionEntry(this);
  154. return ce != null && ce.LoadedPersister.IsInverse;
  155. }
  156. }
  157. /// <summary>
  158. /// Is this the "inverse" end of a bidirectional association with
  159. /// no orphan delete enabled?
  160. /// </summary>
  161. protected bool InverseCollectionNoOrphanDelete
  162. {
  163. get
  164. {
  165. CollectionEntry ce = session.PersistenceContext.GetCollectionEntry(this);
  166. return ce != null && ce.LoadedPersister.IsInverse && !ce.LoadedPersister.HasOrphanDelete;
  167. }
  168. }
  169. /// <summary>
  170. /// Is this the "inverse" end of a bidirectional one-to-many, or
  171. /// of a collection with no orphan delete?
  172. /// </summary>
  173. protected bool InverseOneToManyOrNoOrphanDelete
  174. {
  175. get
  176. {
  177. CollectionEntry ce = session.PersistenceContext.GetCollectionEntry(this);
  178. return
  179. ce != null && ce.LoadedPersister.IsInverse
  180. && (ce.LoadedPersister.IsOneToMany || !ce.LoadedPersister.HasOrphanDelete);
  181. }
  182. }
  183. /// <summary>
  184. /// Return the user-visible collection (or array) instance
  185. /// </summary>
  186. /// <returns>
  187. /// By default, the NHibernate wrapper is an acceptable collection for
  188. /// the end user code to work with because it is interface compatible.
  189. /// An NHibernate PersistentList is an IList, an NHibernate PersistentMap is an IDictionary
  190. /// and those are the types user code is expecting.
  191. /// </returns>
  192. public virtual object GetValue()
  193. {
  194. return this;
  195. }
  196. public virtual bool RowUpdatePossible
  197. {
  198. get { return true; }
  199. }
  200. /// <summary></summary>
  201. protected virtual ISessionImplementor Session
  202. {
  203. get { return session; }
  204. }
  205. public virtual object Owner
  206. {
  207. get { return owner; }
  208. set { owner = value; }
  209. }
  210. public void ClearDirty()
  211. {
  212. dirty = false;
  213. }
  214. public void Dirty()
  215. {
  216. dirty = true;
  217. }
  218. /// <summary>
  219. /// Is the initialized collection empty?
  220. /// </summary>
  221. public abstract bool Empty { get; } //Careful: these methods do not initialize the collection.
  222. /// <summary>
  223. /// Called by any read-only method of the collection interface
  224. /// </summary>
  225. public virtual void Read()
  226. {
  227. Initialize(false);
  228. }
  229. /// <summary> Called by the <tt>Count</tt> property</summary>
  230. protected virtual bool ReadSize()
  231. {
  232. if (!initialized)
  233. {
  234. if (cachedSize != -1 && !HasQueuedOperations)
  235. {
  236. return true;
  237. }
  238. else
  239. {
  240. ThrowLazyInitializationExceptionIfNotConnected();
  241. CollectionEntry entry = session.PersistenceContext.GetCollectionEntry(this);
  242. ICollectionPersister persister = entry.LoadedPersister;
  243. if (persister.IsExtraLazy)
  244. {
  245. if (HasQueuedOperations)
  246. {
  247. session.Flush();
  248. }
  249. cachedSize = persister.GetSize(entry.LoadedKey, session);
  250. return true;
  251. }
  252. }
  253. }
  254. Read();
  255. return false;
  256. }
  257. protected virtual bool? ReadIndexExistence(object index)
  258. {
  259. if (!initialized)
  260. {
  261. ThrowLazyInitializationExceptionIfNotConnected();
  262. CollectionEntry entry = session.PersistenceContext.GetCollectionEntry(this);
  263. ICollectionPersister persister = entry.LoadedPersister;
  264. if (persister.IsExtraLazy)
  265. {
  266. if (HasQueuedOperations)
  267. {
  268. session.Flush();
  269. }
  270. return persister.IndexExists(entry.LoadedKey, index, session);
  271. }
  272. }
  273. Read();
  274. return null;
  275. }
  276. protected virtual bool? ReadElementExistence(object element)
  277. {
  278. if (!initialized)
  279. {
  280. ThrowLazyInitializationExceptionIfNotConnected();
  281. CollectionEntry entry = session.PersistenceContext.GetCollectionEntry(this);
  282. ICollectionPersister persister = entry.LoadedPersister;
  283. if (persister.IsExtraLazy)
  284. {
  285. if (HasQueuedOperations)
  286. {
  287. session.Flush();
  288. }
  289. return persister.ElementExists(entry.LoadedKey, element, session);
  290. }
  291. }
  292. Read();
  293. return null;
  294. }
  295. protected virtual object ReadElementByIndex(object index)
  296. {
  297. if (!initialized)
  298. {
  299. ThrowLazyInitializationExceptionIfNotConnected();
  300. CollectionEntry entry = session.PersistenceContext.GetCollectionEntry(this);
  301. ICollectionPersister persister = entry.LoadedPersister;
  302. if (persister.IsExtraLazy)
  303. {
  304. if (HasQueuedOperations)
  305. {
  306. session.Flush();
  307. }
  308. var elementByIndex = persister.GetElementByIndex(entry.LoadedKey, index, session, owner);
  309. return persister.NotFoundObject == elementByIndex ? NotFound : elementByIndex;
  310. }
  311. }
  312. Read();
  313. return Unknown;
  314. }
  315. /// <summary>
  316. /// Called by any writer method of the collection interface
  317. /// </summary>
  318. protected virtual void Write()
  319. {
  320. Initialize(true);
  321. Dirty();
  322. }
  323. /// <summary>
  324. /// Queue an addition, delete etc. if the persistent collection supports it
  325. /// </summary>
  326. protected virtual void QueueOperation(IDelayedOperation element)
  327. {
  328. if (operationQueue == null)
  329. {
  330. operationQueue = new List<IDelayedOperation>(10);
  331. }
  332. operationQueue.Add(element);
  333. dirty = true; //needed so that we remove this collection from the second-level cache
  334. }
  335. /// <summary>
  336. /// After reading all existing elements from the database,
  337. /// add the queued elements to the underlying collection.
  338. /// </summary>
  339. protected virtual void PerformQueuedOperations()
  340. {
  341. for (int i = 0; i < operationQueue.Count; i++)
  342. {
  343. operationQueue[i].Operate();
  344. }
  345. }
  346. public void SetSnapshot(object key, string role, object snapshot)
  347. {
  348. this.key = key;
  349. this.role = role;
  350. storedSnapshot = snapshot;
  351. }
  352. /// <summary>
  353. /// Clears out any Queued operation.
  354. /// </summary>
  355. /// <remarks>
  356. /// After flushing, clear any "queued" additions, since the
  357. /// database state is now synchronized with the memory state.
  358. /// </remarks>
  359. public virtual void PostAction()
  360. {
  361. operationQueue = null;
  362. cachedSize = -1;
  363. ClearDirty();
  364. }
  365. /// <summary>
  366. /// Called just before reading any rows from the <see cref="IDataReader" />
  367. /// </summary>
  368. public virtual void BeginRead()
  369. {
  370. // override on some subclasses
  371. initializing = true;
  372. }
  373. /// <summary>
  374. /// Called after reading all rows from the <see cref="IDataReader" />
  375. /// </summary>
  376. /// <remarks>
  377. /// This should be overridden by sub collections that use temporary collections
  378. /// to store values read from the db.
  379. /// </remarks>
  380. public virtual bool EndRead(ICollectionPersister persister)
  381. {
  382. // override on some subclasses
  383. return AfterInitialize(persister);
  384. }
  385. public virtual bool AfterInitialize(ICollectionPersister persister)
  386. {
  387. SetInitialized();
  388. //do this bit after setting initialized to true or it will recurse
  389. if (operationQueue != null)
  390. {
  391. PerformQueuedOperations();
  392. operationQueue = null;
  393. cachedSize = -1;
  394. return false;
  395. }
  396. else
  397. {
  398. return true;
  399. }
  400. }
  401. /// <summary>
  402. /// Initialize the collection, if possible, wrapping any exceptions
  403. /// in a runtime exception
  404. /// </summary>
  405. /// <param name="writing">currently obsolete</param>
  406. /// <exception cref="LazyInitializationException">if we cannot initialize</exception>
  407. protected virtual void Initialize(bool writing)
  408. {
  409. if (!initialized)
  410. {
  411. if (initializing)
  412. {
  413. throw new LazyInitializationException("illegal access to loading collection");
  414. }
  415. ThrowLazyInitializationExceptionIfNotConnected();
  416. session.InitializeCollection(this, writing);
  417. }
  418. }
  419. protected void ThrowLazyInitializationExceptionIfNotConnected()
  420. {
  421. if (!IsConnectedToSession)
  422. {
  423. ThrowLazyInitializationException("no session or session was closed");
  424. }
  425. if (!session.IsConnected)
  426. {
  427. ThrowLazyInitializationException("session is disconnected");
  428. }
  429. }
  430. protected void ThrowLazyInitializationException(string message)
  431. {
  432. var ownerEntityName = role == null ? "Unavailable" : StringHelper.Qualifier(role);
  433. throw new LazyInitializationException(ownerEntityName, key, "failed to lazily initialize a collection"
  434. + (role == null ? "" : " of role: " + role) + ", " + message);
  435. }
  436. /// <summary>
  437. /// Mark the collection as initialized.
  438. /// </summary>
  439. protected virtual void SetInitialized()
  440. {
  441. initializing = false;
  442. initialized = true;
  443. }
  444. /// <summary>
  445. /// Gets a <see cref="Boolean"/> indicating if the underlying collection is directly
  446. /// accessible through code.
  447. /// </summary>
  448. /// <value>
  449. /// <see langword="true" /> if we are not guaranteed that the NHibernate collection wrapper
  450. /// is being used.
  451. /// </value>
  452. /// <remarks>
  453. /// This is typically <see langword="false" /> whenever a transient object that contains a collection is being
  454. /// associated with an <see cref="ISession" /> through <see cref="ISession.Save(object)" /> or <see cref="ISession.SaveOrUpdate(object)" />.
  455. /// NHibernate can't guarantee that it will know about all operations that would cause NHibernate's collections
  456. /// to call <see cref="Read()" /> or <see cref="Write" />.
  457. /// </remarks>
  458. public virtual bool IsDirectlyAccessible
  459. {
  460. get { return directlyAccessible; }
  461. protected set { directlyAccessible = value; }
  462. }
  463. /// <summary>
  464. /// Disassociate this collection from the given session.
  465. /// </summary>
  466. /// <param name="currentSession"></param>
  467. /// <returns>true if this was currently associated with the given session</returns>
  468. public bool UnsetSession(ISessionImplementor currentSession)
  469. {
  470. if (currentSession == session)
  471. {
  472. session = null;
  473. return true;
  474. }
  475. else
  476. {
  477. return false;
  478. }
  479. }
  480. /// <summary>
  481. /// Associate the collection with the given session.
  482. /// </summary>
  483. /// <param name="session"></param>
  484. /// <returns>false if the collection was already associated with the session</returns>
  485. public virtual bool SetCurrentSession(ISessionImplementor session)
  486. {
  487. if (session == this.session // NH: added to fix NH-704
  488. && session.PersistenceContext.ContainsCollection(this))
  489. {
  490. return false;
  491. }
  492. else
  493. {
  494. if (IsConnectedToSession)
  495. {
  496. CollectionEntry ce = session.PersistenceContext.GetCollectionEntry(this);
  497. if (ce == null)
  498. {
  499. throw new HibernateException("Illegal attempt to associate a collection with two open sessions");
  500. }
  501. else
  502. {
  503. throw new HibernateException("Illegal attempt to associate a collection with two open sessions: "
  504. + MessageHelper.CollectionInfoString(ce.LoadedPersister, this, ce.LoadedKey, session));
  505. }
  506. }
  507. else
  508. {
  509. this.session = session;
  510. return true;
  511. }
  512. }
  513. }
  514. /// <summary>
  515. /// Gets a <see cref="Boolean"/> indicating if the rows for this collection
  516. /// need to be recreated in the table.
  517. /// </summary>
  518. /// <param name="persister">The <see cref="ICollectionPersister"/> for this Collection.</param>
  519. /// <returns>
  520. /// <see langword="false" /> by default since most collections can determine which rows need to be
  521. /// individually updated/inserted/deleted. Currently only <see cref="PersistentGenericBag{T}"/>'s for <c>many-to-many</c>
  522. /// need to be recreated.
  523. /// </returns>
  524. public virtual bool NeedsRecreate(ICollectionPersister persister)
  525. {
  526. return false;
  527. }
  528. /// <summary>
  529. /// To be called internally by the session, forcing
  530. /// immediate initialization.
  531. /// </summary>
  532. /// <remarks>
  533. /// This method is similar to <see cref="Initialize" />, except that different exceptions are thrown.
  534. /// </remarks>
  535. public virtual void ForceInitialization()
  536. {
  537. if (!initialized)
  538. {
  539. if (initializing)
  540. {
  541. throw new AssertionFailure("force initialize loading collection");
  542. }
  543. if (session == null)
  544. {
  545. throw new HibernateException("collection is not associated with any session");
  546. }
  547. if (!session.IsConnected)
  548. {
  549. throw new HibernateException("disconnected session");
  550. }
  551. session.InitializeCollection(this, false);
  552. }
  553. }
  554. /// <summary>
  555. /// Gets the Snapshot from the current session the collection is in.
  556. /// </summary>
  557. protected virtual object GetSnapshot()
  558. {
  559. return session.PersistenceContext.GetSnapshot(this);
  560. }
  561. /// <summary> Is this instance initialized?</summary>
  562. public bool WasInitialized
  563. {
  564. get { return initialized; }
  565. }
  566. /// <summary> Does this instance have any "queued" additions?</summary>
  567. public bool HasQueuedOperations
  568. {
  569. get { return operationQueue != null && operationQueue.Count > 0; }
  570. }
  571. /// <summary></summary>
  572. public IEnumerable QueuedAdditionIterator
  573. {
  574. get
  575. {
  576. if (HasQueuedOperations)
  577. {
  578. return new AdditionEnumerable(this);
  579. }
  580. else
  581. {
  582. return CollectionHelper.EmptyEnumerable;
  583. }
  584. }
  585. }
  586. public ICollection GetQueuedOrphans(string entityName)
  587. {
  588. if (HasQueuedOperations)
  589. {
  590. List<object> additions = new List<object>(operationQueue.Count);
  591. List<object> removals = new List<object>(operationQueue.Count);
  592. for (int i = 0; i < operationQueue.Count; i++)
  593. {
  594. IDelayedOperation op = operationQueue[i];
  595. if (op.AddedInstance != null)
  596. {
  597. additions.Add(op.AddedInstance);
  598. }
  599. if (op.Orphan != null)
  600. {
  601. removals.Add(op.Orphan);
  602. }
  603. }
  604. return GetOrphans(removals, additions, entityName, session);
  605. }
  606. return CollectionHelper.EmptyCollection;
  607. }
  608. /// <summary>
  609. /// Called before inserting rows, to ensure that any surrogate keys are fully generated
  610. /// </summary>
  611. /// <param name="persister"></param>
  612. public virtual void PreInsert(ICollectionPersister persister) {}
  613. /// <summary>
  614. /// Called after inserting a row, to fetch the natively generated id
  615. /// </summary>
  616. public virtual void AfterRowInsert(ICollectionPersister persister, object entry, int i, object id) { }
  617. /// <summary>
  618. /// Get all "orphaned" elements
  619. /// </summary>
  620. public abstract ICollection GetOrphans(object snapshot, string entityName);
  621. /// <summary>
  622. /// Given a collection of entity instances that used to
  623. /// belong to the collection, and a collection of instances
  624. /// that currently belong, return a collection of orphans
  625. /// </summary>
  626. protected virtual ICollection GetOrphans(ICollection oldElements, ICollection currentElements, string entityName, ISessionImplementor session)
  627. {
  628. // short-circuit(s)
  629. if (currentElements.Count == 0)
  630. {
  631. // no new elements, the old list contains only Orphans
  632. return oldElements;
  633. }
  634. if (oldElements.Count == 0)
  635. {
  636. // no old elements, so no Orphans neither
  637. return oldElements;
  638. }
  639. IType idType = session.Factory.GetEntityPersister(entityName).IdentifierType;
  640. // create the collection holding the orphans
  641. List<object> res = new List<object>();
  642. // collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
  643. var currentIds = new HashSet<TypedValue>();
  644. foreach (object current in currentElements)
  645. {
  646. if (current != null && ForeignKeys.IsNotTransient(entityName, current, null, session))
  647. {
  648. object currentId = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, current, session);
  649. currentIds.Add(new TypedValue(idType, currentId, session.EntityMode));
  650. }
  651. }
  652. // iterate over the *old* list
  653. foreach (object old in oldElements)
  654. {
  655. object oldId = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, old, session);
  656. if (!currentIds.Contains(new TypedValue(idType, oldId, session.EntityMode)))
  657. {
  658. res.Add(old);
  659. }
  660. }
  661. return res;
  662. }
  663. public void IdentityRemove(IList list, object obj, string entityName, ISessionImplementor session)
  664. {
  665. if (obj != null && ForeignKeys.IsNotTransient(entityName, obj, null, session))
  666. {
  667. IType idType = session.Factory.GetEntityPersister(entityName).IdentifierType;
  668. object idOfCurrent = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, obj, session);
  669. List<object> toRemove = new List<object>(list.Count);
  670. foreach (object current in list)
  671. {
  672. if (current == null)
  673. {
  674. continue;
  675. }
  676. object idOfOld = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, current, session);
  677. if (idType.IsEqual(idOfCurrent, idOfOld, session.EntityMode, session.Factory))
  678. {
  679. toRemove.Add(current);
  680. }
  681. }
  682. foreach (object ro in toRemove)
  683. {
  684. list.Remove(ro);
  685. }
  686. }
  687. }
  688. public virtual object GetIdentifier(object entry, int i)
  689. {
  690. throw new NotSupportedException();
  691. }
  692. /// <summary>
  693. /// Disassemble the collection, ready for the cache
  694. /// </summary>
  695. /// <param name="persister"></param>
  696. /// <returns></returns>
  697. public abstract object Disassemble(ICollectionPersister persister);
  698. /// <summary>
  699. /// Is this the wrapper for the given underlying collection instance?
  700. /// </summary>
  701. /// <param name="collection"></param>
  702. /// <returns></returns>
  703. public abstract bool IsWrapper(object collection);
  704. /// <summary>
  705. /// Does an element exist at this entry in the collection?
  706. /// </summary>
  707. /// <param name="entry"></param>
  708. /// <param name="i"></param>
  709. /// <returns></returns>
  710. public abstract bool EntryExists(object entry, int i);
  711. /// <summary>
  712. /// Get all the elements that need deleting
  713. /// </summary>
  714. public abstract IEnumerable GetDeletes(ICollectionPersister persister, bool indexIsFormula);
  715. public abstract bool IsSnapshotEmpty(object snapshot);
  716. public abstract IEnumerable Entries(ICollectionPersister persister);
  717. public abstract object GetSnapshot(ICollectionPersister persister);
  718. public abstract bool EqualsSnapshot(ICollectionPersister persister);
  719. public abstract object GetElement(object entry);
  720. /// <summary>
  721. /// Read the state of the collection from a disassembled cached value.
  722. /// </summary>
  723. /// <param name="persister"></param>
  724. /// <param name="disassembled"></param>
  725. /// <param name="owner"></param>
  726. public abstract void InitializeFromCache(ICollectionPersister persister, object disassembled, object owner);
  727. /// <summary>
  728. /// Do we need to update this element?
  729. /// </summary>
  730. /// <param name="entry"></param>
  731. /// <param name="i"></param>
  732. /// <param name="elemType"></param>
  733. /// <returns></returns>
  734. public abstract bool NeedsUpdating(object entry, int i, IType elemType);
  735. /// <summary>
  736. /// Reads the row from the <see cref="IDataReader"/>.
  737. /// </summary>
  738. /// <param name="reader">The IDataReader that contains the value of the Identifier</param>
  739. /// <param name="role">The persister for this Collection.</param>
  740. /// <param name="descriptor">The descriptor providing result set column names</param>
  741. /// <param name="owner">The owner of this Collection.</param>
  742. /// <returns>The object that was contained in the row.</returns>
  743. public abstract object ReadFrom(IDataReader reader, ICollectionPersister role, ICollectionAliases descriptor,
  744. object owner);
  745. public abstract object GetSnapshotElement(object entry, int i);
  746. /// <summary>
  747. /// Do we need to insert this element?
  748. /// </summary>
  749. /// <param name="entry"></param>
  750. /// <param name="i"></param>
  751. /// <param name="elemType"></param>
  752. /// <returns></returns>
  753. public abstract bool NeedsInserting(object entry, int i, IType elemType);
  754. /// <summary>
  755. /// Get the index of the given collection entry
  756. /// </summary>
  757. public abstract object GetIndex(object entry, int i, ICollectionPersister persister);
  758. /// <summary>
  759. /// Called before any elements are read into the collection,
  760. /// allowing appropriate initializations to occur.
  761. /// </summary>
  762. /// <param name="persister">The underlying collection persister. </param>
  763. /// <param name="anticipatedSize">The anticipated size of the collection after initialization is complete. </param>
  764. public abstract void BeforeInitialize(ICollectionPersister persister, int anticipatedSize);
  765. #region - Hibernate Collection Proxy Classes
  766. /*
  767. * These were needed by Hibernate because Java's collections provide methods
  768. * to get sublists, modify a collection with an iterator - all things that
  769. * Hibernate needs to be made aware of. If .net changes their collection interfaces
  770. * then we can readd these back in.
  771. */
  772. #endregion
  773. }
  774. }