示例#1
0
        /// <summary> 
        /// Finish the process of collection-loading for this bound result set.  Mainly this
        /// involves cleaning up resources and notifying the collections that loading is
        /// complete. 
        /// </summary>
        /// <param name="persister">The persister for which to complete loading. </param>
        public void EndLoadingCollections(ICollectionPersister persister)
        {
            if (!loadContexts.HasLoadingCollectionEntries || (localLoadingCollectionKeys.Count == 0))
            {
                return;
            }

            // in an effort to avoid concurrent-modification-exceptions (from
            // potential recursive calls back through here as a result of the
            // eventual call to PersistentCollection#endRead), we scan the
            // internal loadingCollections map for matches and store those matches
            // in a temp collection.  the temp collection is then used to "drive"
            // the #endRead processing.
            List<CollectionKey> toRemove = new List<CollectionKey>();
            List<LoadingCollectionEntry> matches =new List<LoadingCollectionEntry>();
            foreach (CollectionKey collectionKey in localLoadingCollectionKeys)
            {
                ISessionImplementor session = LoadContext.PersistenceContext.Session;

                LoadingCollectionEntry lce = loadContexts.LocateLoadingCollectionEntry(collectionKey);
                if (lce == null)
                {
                    log.Warn("In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [" + collectionKey + "], but no LoadingCollectionEntry was found in loadContexts");
                }
                else if (lce.ResultSet == resultSet && lce.Persister == persister)
                {
                    matches.Add(lce);
                    if (lce.Collection.Owner == null)
                    {
                        session.PersistenceContext.AddUnownedCollection(new CollectionKey(persister, lce.Key, session.EntityMode),
                                                                        lce.Collection);
                    }
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("removing collection load entry [" + lce + "]");
                    }

                    // todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
                    loadContexts.UnregisterLoadingCollectionXRef(collectionKey);
                    toRemove.Add(collectionKey);
                }
            }
            localLoadingCollectionKeys.RemoveAll(toRemove);

            EndLoadingCollections(persister, matches);
            if ((localLoadingCollectionKeys.Count == 0))
            {
                // todo : hack!!!
                // NOTE : here we cleanup the load context when we have no more local
                // LCE entries.  This "works" for the time being because really
                // only the collection load contexts are implemented.  Long term,
                // this cleanup should become part of the "close result set"
                // processing from the (sandbox/jdbc) jdbc-container code.
                loadContexts.Cleanup(resultSet);
            }
        }
		public override ICollection GetSnapshot(ICollectionPersister persister)
		{
			EntityMode entityMode = Session.EntityMode;

			List<object> clonedList = new List<object>(list.Count);
			foreach (object current in list)
			{
				object deepCopy = persister.ElementType.DeepCopy(current, entityMode, persister.Factory);
				clonedList.Add(deepCopy);
			}
			return clonedList;
		}
        public override IAuditWorkUnit Dispatch(IWorkUnitMergeVisitor first)
        {
            if (first is PersistentCollectionChangeWorkUnit) {
                PersistentCollectionChangeWorkUnit original = (PersistentCollectionChangeWorkUnit) first;

                // Merging the collection changes in both work units.

                // First building a map from the ids of the collection-entry-entities from the "second" collection changes,
                // to the PCCD objects. That way, we will be later able to check if an "original" collection change
                // should be added, or if it is overshadowed by a new one.
                IDictionary<Object, PersistentCollectionChangeData> newChangesIdMap = new Dictionary<Object, PersistentCollectionChangeData>();
                foreach (PersistentCollectionChangeData persistentCollectionChangeData in getCollectionChanges()) {
                    newChangesIdMap.Add(
                            getOriginalId(persistentCollectionChangeData),
                            persistentCollectionChangeData);
                }

                // This will be the list with the resulting (merged) changes.
                List<PersistentCollectionChangeData> mergedChanges = new List<PersistentCollectionChangeData>();

                // Including only those original changes, which are not overshadowed by new ones.
                foreach (PersistentCollectionChangeData originalCollectionChangeData in original.getCollectionChanges()) {
                    if (!newChangesIdMap.ContainsKey(getOriginalId(originalCollectionChangeData))) {
                        mergedChanges.Add(originalCollectionChangeData);
                    }
                }

                // Finally adding all of the new changes to the end of the list
                mergedChanges = (List<PersistentCollectionChangeData>)mergedChanges.Concat(getCollectionChanges());

                return new PersistentCollectionChangeWorkUnit(sessionImplementor, EntityName, verCfg, EntityId, mergedChanges,
                        ReferencingPropertyName);
            } else {
                throw new Exception("Trying to merge a " + first + " with a PersitentCollectionChangeWorkUnit. " +
                        "This is not really possible.");
            }
        }
示例#4
0
		public override string ToLoggableString(object value, ISessionFactoryImplementor factory)
		{
			if (value == null)
			{
				return "null";
			}
			Array array = (Array) value;
			int length = array.Length;
			IList list = new List<object>(length);
			IType elemType = GetElementType(factory);
			for (int i = 0; i < length; i++)
			{
				list.Add(elemType.ToLoggableString(array.GetValue(i), factory));
			}
			return CollectionPrinter.ToString(list);
		}
示例#5
0
		/// <summary>
		/// Adds an association and extracts the aliases the association's 'with clause' is dependent on
		/// </summary>
		private void AddAssociation(string subalias, OuterJoinableAssociation association)
		{
			subalias = subalias.ToLower();

			var dependencies = new List<string>();
			var on = association.On.ToString();
			if (!String.IsNullOrEmpty(on))
			{
				foreach (Match match in aliasRegex.Matches(on))
				{
					string alias = match.Groups[1].Value;
					if (alias == subalias) continue;
					dependencies.Add(alias.ToLower());
				}
			}

			_dependentAliases.Add(new DependentAlias
			{
				Alias = subalias,
				DependsOn = dependencies.ToArray()
			});

			associations.Add(association);
		}
示例#6
0
		private IList DoQuery(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies)
		{
			RowSelection selection = queryParameters.RowSelection;
			int maxRows = HasMaxRows(selection) ? selection.MaxRows : int.MaxValue;

			int entitySpan = EntityPersisters.Length;

			List<object> hydratedObjects = entitySpan == 0 ? null : new List<object>(entitySpan * 10);

			IDbCommand st = PrepareQueryCommand(queryParameters, false, session);

			IDataReader rs = GetResultSet(st, queryParameters.HasAutoDiscoverScalarTypes, queryParameters.Callable, selection,
			                              session);

			// would be great to move all this below here into another method that could also be used
			// from the new scrolling stuff.
			//
			// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
			// that I could do the control breaking at the means to know when to stop
			LockMode[] lockModeArray = GetLockModes(queryParameters.LockModes);
			EntityKey optionalObjectKey = GetOptionalObjectKey(queryParameters, session);

			bool createSubselects = IsSubselectLoadingEnabled;
			List<EntityKey[]> subselectResultKeys = createSubselects ? new List<EntityKey[]>() : null;
			IList results = new List<object>();

			try
			{
				HandleEmptyCollections(queryParameters.CollectionKeys, rs, session);
				EntityKey[] keys = new EntityKey[entitySpan]; // we can reuse it each time

				if (log.IsDebugEnabled)
				{
					log.Debug("processing result set");
				}

				int count;
				for (count = 0; count < maxRows && rs.Read(); count++)
				{
					if (log.IsDebugEnabled)
					{
						log.Debug("result set row: " + count);
					}

					object result = GetRowFromResultSet(rs, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects,
					                                    keys, returnProxies);
					results.Add(result);

					if (createSubselects)
					{
						subselectResultKeys.Add(keys);
						keys = new EntityKey[entitySpan]; //can't reuse in this case
					}
				}

				if (log.IsDebugEnabled)
				{
					log.Debug(string.Format("done processing result set ({0} rows)", count));
				}
			}
			catch (Exception e)
			{
				e.Data["actual-sql-query"] = st.CommandText;
				throw;
			}
			finally
			{
				session.Batcher.CloseCommand(st, rs);
			}

			InitializeEntitiesAndCollections(hydratedObjects, rs, session, queryParameters.ReadOnly);

			if (createSubselects)
			{
				CreateSubselects(subselectResultKeys, queryParameters, session);
			}

			return results;
		}
		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;
		}
		/// <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>();
		}
		private void InitTransientState()
		{
			loadContexts = null;
			nullAssociations = new HashedSet<AssociationKey>();
			nonlazyCollections = new List<IPersistentCollection>(InitCollectionSize);
		}
		public override bool AfterInitialize(ICollectionPersister persister)
		{
			// NH Different behavior : NH-739
			// would be nice to prevent this overhead but the operation is managed where the ICollectionPersister is not available
			bool result;
			if (persister.IsOneToMany && HasQueuedOperations)
			{
				int additionStartFrom = bag.Count;
				IList additionQueue = new List<object>(additionStartFrom);
				foreach (object o in QueuedAdditionIterator)
				{
					if (o != null)
					{
						for (int i = 0; i < bag.Count; i++)
						{
							// we are using ReferenceEquals to be sure that is exactly the same queued instance 
							if (ReferenceEquals(o, bag[i]))
							{
								additionQueue.Add(o);
								break;
							}
						}
					}
				}

				result = base.AfterInitialize(persister);

				if(!result)
				{
					// removing duplicated additions
					foreach (object o in additionQueue)
					{
						for (int i = additionStartFrom; i < bag.Count; i++)
						{
							if (ReferenceEquals(o, bag[i]))
							{
								bag.RemoveAt(i);
								break;
							}
						}
					}
				}
			}
			else
			{
				result = base.AfterInitialize(persister);
			}
			return result;
		}
		/// <summary> 
		/// 1. Recreate the collection key -> collection map
		/// 2. rebuild the collection entries
		/// 3. call Interceptor.postFlush()
		/// </summary>
		protected virtual void PostFlush(ISessionImplementor session)
		{
			if (log.IsDebugEnabled)
			{
				log.Debug("post flush");
			}

			IPersistenceContext persistenceContext = session.PersistenceContext;
			persistenceContext.CollectionsByKey.Clear();
			persistenceContext.BatchFetchQueue.ClearSubselects();
			//the database has changed now, so the subselect results need to be invalidated

			// NH Different implementation: In NET an iterator is immutable;
			// we need something to hold the persistent collection to remove, and it must be less intrusive as possible
			IDictionary cEntries = persistenceContext.CollectionEntries;
			List<IPersistentCollection> keysToRemove = new List<IPersistentCollection>(cEntries.Count);
			foreach (DictionaryEntry me in cEntries)
			{
				CollectionEntry collectionEntry = (CollectionEntry) me.Value;
				IPersistentCollection persistentCollection = (IPersistentCollection) me.Key;
				collectionEntry.PostFlush(persistentCollection);
				if (collectionEntry.LoadedPersister == null)
				{
					keysToRemove.Add(persistentCollection);
				}
				else
				{
					//otherwise recreate the mapping between the collection and its key
					CollectionKey collectionKey =
						new CollectionKey(collectionEntry.LoadedPersister, collectionEntry.LoadedKey, session.EntityMode);
					persistenceContext.CollectionsByKey[collectionKey] = persistentCollection;
				}
			}
			foreach (IPersistentCollection key in keysToRemove)
			{
				persistenceContext.CollectionEntries.Remove(key);
			}
			session.Interceptor.PostFlush((ICollection) persistenceContext.EntitiesByKey.Values);
		}
		public override IEnumerable GetDeletes(ICollectionPersister persister, bool indexIsFormula)
		{
			IList deletes = new List<object>();
			IList sn = (IList) GetSnapshot();
			int end;
			if (sn.Count > list.Count)
			{
				for (int i = list.Count; i < sn.Count; i++)
				{
					deletes.Add(indexIsFormula ? sn[i] : i);
				}
				end = list.Count;
			}
			else
			{
				end = sn.Count;
			}
			for (int i = 0; i < end; i++)
			{
				if (list[i] == null && sn[i] != null)
				{
					deletes.Add(indexIsFormula ? sn[i] : i);
				}
			}
			return deletes;
		}
		public override IEnumerable GetDeletes(ICollectionPersister persister, bool indexIsFormula)
		{
			IList deletes = new List<object>();
			IDictionary sn = (IDictionary) GetSnapshot();
			foreach (DictionaryEntry e in sn)
			{
				object key = e.Key;
				if (!map.Contains(key))
				{
					deletes.Add(indexIsFormula ? e.Value : key);
				}
			}
			return deletes;
		}
示例#14
0
		/// <returns><see cref="IList" /> of <see cref="IType" /></returns>
		protected SqlType[] GetParameterTypes(QueryParameters parameters, bool addLimit, bool addOffset)
		{
			List<IType> paramTypeList = new List<IType>();
			int span = 0;

			for (int index = 0; index < parameters.PositionalParameterTypes.Length; index++)
			{
				int location = parameters.PositionalParameterLocations[index];
				location = parameters.FindAdjustedParameterLocation(location);
				IType type = parameters.PositionalParameterTypes[index];
				ArrayHelper.SafeSetValue(paramTypeList, location, type);
				span += type.GetColumnSpan(Factory);
			}

			for (int index = 0; index < parameters.FilteredParameterTypes.Count; index++)
			{
				int location = parameters.FilteredParameterLocations[index];
				IType type = parameters.FilteredParameterTypes[index];
				ArrayHelper.SafeSetValue(paramTypeList, location, type);
				span += type.GetColumnSpan(Factory);
			}

			if (parameters.NamedParameters != null && parameters.NamedParameters.Count > 0)
			{
				// convert the named parameters to an array of types
				foreach (KeyValuePair<string, TypedValue> namedParameter in parameters.NamedParameters)
				{
					string name = namedParameter.Key;
					TypedValue typedval = namedParameter.Value;
					int[] locs = GetNamedParameterLocs(name);
					span += typedval.Type.GetColumnSpan(Factory) * locs.Length;

					for (int i = 0; i < locs.Length; i++)
					{
						int location = locs[i];
						location = parameters.FindAdjustedParameterLocation(location);

						// can still clash with positional parameters
						//  could consider throwing an exception to locate problem (NH-1098)
						while ((location < paramTypeList.Count) && (paramTypeList[location] != null))
							location++;

						ArrayHelper.SafeSetValue(paramTypeList, location, typedval.Type);
					}
				}
			}

			if (addLimit && Factory.Dialect.SupportsVariableLimit)
			{
				if (Factory.Dialect.BindLimitParametersFirst)
				{
					paramTypeList.Insert(0, NHibernateUtil.Int32);
					if (addOffset)
					{
						paramTypeList.Insert(0, NHibernateUtil.Int32);
					}
				}
				else
				{
					paramTypeList.Add(NHibernateUtil.Int32);
					if (addOffset)
					{
						paramTypeList.Add(NHibernateUtil.Int32);
					}
				}

				span += addOffset ? 2 : 1;
			}

			return ConvertITypesToSqlTypes(paramTypeList, span);
		}
示例#15
0
		protected SqlType[] ConvertITypesToSqlTypes(List<IType> nhTypes, int totalSpan)
		{
			SqlType[] result = new SqlType[totalSpan];

			int index = 0;
			foreach (IType type in nhTypes)
			{
				int span = type.SqlTypes(Factory).Length;
				Array.Copy(type.SqlTypes(Factory), 0, result, index, span);
				index += span;
			}

			return result;
		}
		protected internal virtual string RenderLoggableString(object value, ISessionFactoryImplementor factory)
		{
			IList list = new List<object>();
			IType elemType = GetElementType(factory);
			IEnumerable iter = GetElementsIterator(value);
			foreach (object o in iter)
				list.Add(elemType.ToLoggableString(o, factory));

			return CollectionPrinter.ToString(list);
		}
		// For a one-to-many, a <bag> is not really a bag;
		// it is *really* a set, since it can't contain the
		// same element twice. It could be considered a bug
		// in the mapping dtd that <bag> allows <one-to-many>.

		// Anyway, here we implement <set> semantics for a
		// <one-to-many> <bag>!

		public override IEnumerable GetDeletes(ICollectionPersister persister, bool indexIsFormula)
		{
			IType elementType = persister.ElementType;
			EntityMode entityMode = Session.EntityMode;
			List<object> deletes = new List<object>();
			IList sn = (IList) GetSnapshot();
			int i = 0;
			foreach (object old in sn)
			{
				bool found = false;
				if (bag.Count > i && elementType.IsSame(old, bag[i++], entityMode))
				{
					//a shortcut if its location didn't change!
					found = true;
				}
				else
				{
					foreach (object newObject in bag)
					{
						if (elementType.IsSame(old, newObject, entityMode))
						{
							found = true;
							break;
						}
					}
				}
				if (!found)
				{
					deletes.Add(old);
				}
			}
			return deletes;
		}
		void IDeserializationCallback.OnDeserialization(object sender)
		{
			log.Debug("Deserialization callback persistent-context");

			// during deserialization, we need to reconnect all proxies and
			// collections to this session, as well as the EntityEntry and
			// CollectionEntry instances; these associations are transient
			// because serialization is used for different things.
			parentsByChild = IdentityMap.Instantiate(InitCollectionSize);

			// OnDeserialization() must be called manually on all Dictionaries and Hashtables,
			// otherwise they are still empty at this point (the .NET deserialization code calls
			// OnDeserialization() on them AFTER it calls the current method).
			entitiesByKey.OnDeserialization(sender);
			entitiesByUniqueKey.OnDeserialization(sender);
			((IDeserializationCallback)entityEntries).OnDeserialization(sender);
			proxiesByKey.OnDeserialization(sender);
			entitySnapshotsByKey.OnDeserialization(sender);
			((IDeserializationCallback)arrayHolders).OnDeserialization(sender);
			((IDeserializationCallback)collectionEntries).OnDeserialization(sender);
			collectionsByKey.OnDeserialization(sender);

			// If nullifiableEntityKeys is once used in the current method, HashedSets will need
			// an OnDeserialization() method.
			//nullifiableEntityKeys.OnDeserialization(sender);

			if (unownedCollections != null)
			{
				unownedCollections.OnDeserialization(sender);
			}

			// TODO NH: "reconnect" EntityKey with session.factory and create a test for serialization of StatefulPersistenceContext
			foreach (DictionaryEntry collectionEntry in collectionEntries)
			{
				try
				{
					((IPersistentCollection)collectionEntry.Key).SetCurrentSession(session);
					CollectionEntry ce = (CollectionEntry)collectionEntry.Value;
					if (ce.Role != null)
					{
						ce.AfterDeserialize(Session.Factory);
					}

				}
				catch (HibernateException he)
				{
					throw new InvalidOperationException(he.Message);
				}
			}

			List<EntityKey> keysToRemove = new List<EntityKey>();
			foreach (KeyValuePair<EntityKey, INHibernateProxy> p in proxiesByKey)
			{
				if (p.Value != null)
				{
					(p.Value).HibernateLazyInitializer.Session = session;
				}
				else
				{
					// the proxy was pruned during the serialization process because the target had been instantiated.
					keysToRemove.Add(p.Key);
				}
			}
			for (int i = 0; i < keysToRemove.Count; i++)
				proxiesByKey.Remove(keysToRemove[i]);

			foreach (EntityEntry e in entityEntries.Values)
			{
				try
				{
					e.Persister = session.Factory.GetEntityPersister(e.EntityName);
				}
				catch (MappingException me)
				{
					throw new InvalidOperationException(me.Message);
				}
			}
		}
		void IDeserializationCallback.OnDeserialization(object sender)
		{
			log.Debug("Deserialization callback persistent-context");
			// during deserialization, we need to reconnect all proxies and
			// collections to this session, as well as the EntityEntry and
			// CollectionEntry instances; these associations are transient
			// because serialization is used for different things.

			// TODO NH: "reconnect" EntityKey with session.factory and create a test for serialization of StatefulPersistenceContext
			foreach (DictionaryEntry collectionEntry in collectionEntries)
			{
				try
				{
					((IPersistentCollection)collectionEntry.Key).SetCurrentSession(session);
					CollectionEntry ce = (CollectionEntry)collectionEntry.Value;
					if (ce.Role != null)
					{
						ce.AfterDeserialize(Session.Factory);
					}

				}
				catch (HibernateException he)
				{
					throw new InvalidOperationException(he.Message);
				}
			}

			List<EntityKey> keysToRemove = new List<EntityKey>();
			foreach (KeyValuePair<EntityKey, INHibernateProxy> p in proxiesByKey)
			{
				if (p.Value != null)
				{
					(p.Value).HibernateLazyInitializer.Session = session;
				}
				else
				{
					// the proxy was pruned during the serialization process because the target had been instantiated.
					keysToRemove.Add(p.Key);
				}
			}
			for (int i = 0; i < keysToRemove.Count; i++)
				proxiesByKey.Remove(keysToRemove[i]);

			foreach (EntityEntry e in entityEntries.Values)
			{
				try
				{
					e.Persister = session.Factory.GetEntityPersister(e.EntityName);
				}
				catch (MappingException me)
				{
					throw new InvalidOperationException(me.Message);
				}
			}
		}
		/// <summary>
		/// Queue an addition, delete etc. if the persistent collection supports it
		/// </summary>
		protected void QueueOperation(IDelayedOperation element)
		{
			if (operationQueue == null)
			{
				operationQueue = new List<IDelayedOperation>(10);
			}
			operationQueue.Add(element);
			dirty = true; //needed so that we remove this collection from the second-level cache
		}
		/// <summary> 
		/// Remove an entity from the session cache, also clear
		/// up other state associated with the entity, all except
		/// for the <tt>EntityEntry</tt>
		/// </summary>
		public object RemoveEntity(EntityKey key)
		{
			object tempObject = entitiesByKey[key];
			entitiesByKey.Remove(key);
			object entity = tempObject;
			List<EntityUniqueKey> toRemove = new List<EntityUniqueKey>();
			foreach (KeyValuePair<EntityUniqueKey, object> pair in entitiesByUniqueKey)
			{
				if (pair.Value == entity) toRemove.Add(pair.Key);
			}
			foreach (EntityUniqueKey uniqueKey in toRemove)
			{
				entitiesByUniqueKey.Remove(uniqueKey);
			}

			entitySnapshotsByKey.Remove(key);
			nullifiableEntityKeys.Remove(key);
			BatchFetchQueue.RemoveBatchLoadableEntityKey(key);
			BatchFetchQueue.RemoveSubselect(key);
			return entity;
		}
		/// <summary>
		/// Clears out any Queued operation.
		/// </summary>
		/// <remarks>
		/// After flushing, clear any "queued" additions, since the
		/// database state is now synchronized with the memory state.
		/// </remarks>
		public virtual void PostAction()
		{
			operationQueue = null;
			cachedSize = -1;
			ClearDirty();
		}
		/// <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 virtual bool AfterInitialize(ICollectionPersister persister)
		{
			SetInitialized();
			//do this bit after setting initialized to true or it will recurse
			if (operationQueue != null)
			{
				PerformQueuedOperations();
				operationQueue = null;
				cachedSize = -1;
				return false;
			}
			else
			{
				return true;
			}
		}
		public override ICollection GetOrphans(object snapshot, string entityName)
		{
			object[] sn = (object[]) snapshot;
			object[] arr = (object[]) array;
			List<object> result = new List<object>(sn);
			for (int i = 0; i < sn.Length; i++)
			{
				IdentityRemove(result, arr[i], entityName, Session);
			}
			return result;
		}
		public ICollection GetQueuedOrphans(string entityName)
		{
			if (HasQueuedOperations)
			{
				List<object> additions = new List<object>(operationQueue.Count);
				List<object> removals = new List<object>(operationQueue.Count);
				for (int i = 0; i < operationQueue.Count; i++)
				{
					IDelayedOperation op = operationQueue[i];
					if (op.AddedInstance != null)
					{
						additions.Add(op.AddedInstance);
					}
					if (op.Orphan != null)
					{
						removals.Add(op.Orphan);
					}
				}
				return GetOrphans(removals, additions, entityName, session);
			}

			return CollectionHelper.EmptyCollection;
		}
示例#27
0
		private static int[] GetTopologicalSortOrder(List<DependentAlias> fields)
		{
			TopologicalSorter g = new TopologicalSorter(fields.Count);
			Dictionary<string, int> _indexes = new Dictionary<string, int>();

			// add vertices
			for (int i = 0; i < fields.Count; i++)
			{
				_indexes[fields[i].Alias.ToLower()] = g.AddVertex(i);
			}

			// add edges
			for (int i = 0; i < fields.Count; i++)
			{
				if (fields[i].DependsOn != null)
				{
					for (int j = 0; j < fields[i].DependsOn.Length; j++)
					{
						var dependentField = fields[i].DependsOn[j].ToLower();
						if (_indexes.ContainsKey(dependentField))
						{
							g.AddEdge(i, _indexes[dependentField]);
						}
					}
				}
			}

			return g.Sort();
		}
		/// <summary> 
		/// Given a collection of entity instances that used to
		/// belong to the collection, and a collection of instances
		/// that currently belong, return a collection of orphans
		/// </summary>
		protected static ICollection GetOrphans(ICollection oldElements, ICollection currentElements, string entityName,
		                                        ISessionImplementor session)
		{
			// short-circuit(s)
			if (currentElements.Count == 0)
			{
				// no new elements, the old list contains only Orphans
				return oldElements;
			}
			if (oldElements.Count == 0)
			{
				// no old elements, so no Orphans neither
				return oldElements;
			}

			IType idType = session.Factory.GetEntityPersister(entityName).IdentifierType;

			// create the collection holding the orphans
			List<object> res = new List<object>();

			// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
			HashedSet<TypedValue> currentIds = new HashedSet<TypedValue>();
			foreach (object current in currentElements)
			{
				if (current != null && ForeignKeys.IsNotTransient(entityName, current, null, session))
				{
					object currentId = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, current, session);
					currentIds.Add(new TypedValue(idType, currentId, session.EntityMode));
				}
			}

			// iterate over the *old* list
			foreach (object old in oldElements)
			{
				object oldId = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, old, session);
				if (!currentIds.Contains(new TypedValue(idType, oldId, session.EntityMode)))
				{
					res.Add(old);
				}
			}

			return res;
		}
示例#29
0
		/// <summary>
		/// Generate a sequence of <c>LEFT OUTER JOIN</c> clauses for the given associations.
		/// </summary>
		protected JoinFragment MergeOuterJoins(IList<OuterJoinableAssociation> associations)
		{
			IList<OuterJoinableAssociation> sortedAssociations = new List<OuterJoinableAssociation>();

			var indices = GetTopologicalSortOrder(_dependentAliases);
			for (int index = indices.Length - 1; index >= 0; index--)
			{
				sortedAssociations.Add(associations[indices[index]]);
			}

			JoinFragment outerjoin = Dialect.CreateOuterJoinFragment();

			OuterJoinableAssociation last = null;
			foreach (OuterJoinableAssociation oj in sortedAssociations)
			{
				if (last != null && last.IsManyToManyWith(oj))
				{
					oj.AddManyToManyJoin(outerjoin, (IQueryableCollection) last.Joinable);
				}
				else
				{
					oj.AddJoins(outerjoin);
					// NH Different behavior : NH1179 and NH1293
					// Apply filters in Many-To-One association
					if (enabledFiltersForManyToOne.Count > 0)
					{
						string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForManyToOne);
						bool joinClauseDoesNotContainsFilterAlready =
							outerjoin.ToFromFragmentString.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1;
						if (joinClauseDoesNotContainsFilterAlready)
						{
							outerjoin.AddCondition(manyToOneFilterFragment);
						}
					}
				}
				last = oj;
			}

			return outerjoin;
		}
		public static void IdentityRemove(IList list, object obj, string entityName, ISessionImplementor session)
		{
			if (obj != null && ForeignKeys.IsNotTransient(entityName, obj, null, session))
			{
				IType idType = session.Factory.GetEntityPersister(entityName).IdentifierType;

				object idOfCurrent = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, obj, session);
				List<object> toRemove = new List<object>(list.Count);
				foreach (object current in list)
				{
					if (current == null)
					{
						continue;
					}
					object idOfOld = ForeignKeys.GetEntityIdentifierIfNotUnsaved(entityName, current, session);
					if (idType.IsEqual(idOfCurrent, idOfOld, session.EntityMode, session.Factory))
					{
						toRemove.Add(current);
					}
				}
				foreach (object ro in toRemove)
				{
					list.Remove(ro);
				}
			}
		}