public static IndexSearcher BuildSearcher(ISearchFactoryImplementor searchFactory,
                                             out IESI.ISet<System.Type> classesAndSubclasses,
                                             params System.Type[] classes)
        {
            IDictionary<System.Type, DocumentBuilder> builders = searchFactory.DocumentBuilders;
            IESI.ISet<IDirectoryProvider> directories = new IESI.HashedSet<IDirectoryProvider>();
            if (classes == null || classes.Length == 0)
            {
                // no class means all classes
                foreach (DocumentBuilder builder in builders.Values)
                {
                    foreach (IDirectoryProvider provider in builder.DirectoryProvidersSelectionStrategy.GetDirectoryProvidersForAllShards())
                    {
                        directories.Add(provider);
                    }
                }

                // Give them back an empty set
                classesAndSubclasses = null;
            }
            else
            {
                var involvedClasses = new IESI.HashedSet<System.Type>();
                involvedClasses.AddAll(classes);
                foreach (System.Type clazz in classes)
                {
                    DocumentBuilder builder;
                    builders.TryGetValue(clazz, out builder);
                    if (builder != null)
                    {
                        involvedClasses.AddAll(builder.MappedSubclasses);
                    }
                }

                foreach (System.Type clazz in involvedClasses)
                {
                    DocumentBuilder builder;
                    builders.TryGetValue(clazz, out builder);

                    // TODO should we rather choose a polymorphic path and allow non mapped entities
                    if (builder == null)
                    {
                        throw new HibernateException("Not a mapped entity: " + clazz);
                    }

                    foreach (IDirectoryProvider provider in builder.DirectoryProvidersSelectionStrategy.GetDirectoryProvidersForAllShards())
                    {
                        directories.Add(provider);
                    }
                }

                classesAndSubclasses = involvedClasses;
            }

            IDirectoryProvider[] directoryProviders = new List<IDirectoryProvider>(directories).ToArray();
            return new IndexSearcher(searchFactory.ReaderProvider.OpenReader(directoryProviders));
        }
		/// <summary>
		/// Create an action that will evict collection and entity regions based on queryspaces (table names).  
		/// </summary>
		public BulkOperationCleanupAction(ISessionImplementor session, IESI.ISet<string> querySpaces)
		{
			//from H3.2 TODO: cache the autodetected information and pass it in instead.
			this.session = session;

			IESI.ISet<string> tmpSpaces = new IESI.HashedSet<string>(querySpaces);
			ISessionFactoryImplementor factory = session.Factory;
			IDictionary<string, IClassMetadata> acmd = factory.GetAllClassMetadata();
			foreach (KeyValuePair<string, IClassMetadata> entry in acmd)
			{
				string entityName = entry.Key;
				IEntityPersister persister = factory.GetEntityPersister(entityName);
				string[] entitySpaces = persister.QuerySpaces;

				if (AffectedEntity(querySpaces, entitySpaces))
				{
					if (persister.HasCache)
					{
						affectedEntityNames.Add(persister.EntityName);
					}
					IESI.ISet<string> roles = session.Factory.GetCollectionRolesByEntityParticipant(persister.EntityName);
					if (roles != null)
					{
						affectedCollectionRoles.AddAll(roles);
					}
					for (int y = 0; y < entitySpaces.Length; y++)
					{
						tmpSpaces.Add(entitySpaces[y]);
					}
				}
			}
			spaces = new List<string>(tmpSpaces);
		}
		public void UpdateReservedWordsInDialect()
		{
			var reservedDb = new IESI.HashedSet<string>();
			var configuration = TestConfigurationHelper.GetDefaultConfiguration();
			var dialect = Dialect.Dialect.GetDialect(configuration.Properties);
			var connectionHelper = new ManagedProviderConnectionHelper(configuration.Properties);
			connectionHelper.Prepare();
			try
			{
				var metaData = dialect.GetDataBaseSchema(connectionHelper.Connection);
				foreach (var rw in metaData.GetReservedWords())
				{
					reservedDb.Add(rw.ToLowerInvariant());
				}
			}
			finally
			{
				connectionHelper.Release();
			}

			var sf = (ISessionFactoryImplementor) configuration.BuildSessionFactory();
			SchemaMetadataUpdater.Update(sf);
			var match = reservedDb.Intersect(sf.Dialect.Keywords);
			Assert.That(match, Is.EquivalentTo(reservedDb));
		}
示例#4
0
        public static void Synchronize(DirectoryInfo source, DirectoryInfo destination, bool smart)
        {
            if (!destination.Exists)
            {
                destination.Create();
            }

            FileInfo[] sources = source.GetFiles();
            IESI.ISet<string> srcNames = new IESI.HashedSet<string>();
            foreach (FileInfo fileInfo in sources)
            {
                srcNames.Add(fileInfo.Name);
            }

            FileInfo[] dests = destination.GetFiles();

            // Delete files not present in source
            foreach (FileInfo file in dests)
            {
                if (!srcNames.Contains(file.Name))
                {
                    try
                    {
                        /*
                         * Try to delete, could fail because windows don't permit a file to be
                         * deleted while it is in use. If it is the case, the file would be deleted 
                         * when the index is reopened or in the next synchronization. 
                         */
                        file.Delete();
                    }
                    catch (IOException e)
                    {
                        if (log.IsWarnEnabled)
                        {
                            log.Warn("Unable to delete file " + file.Name + ", maybe in use per another reader", e);
                        }
                    }
                }
            }

            // Copy each file from source
            foreach (FileInfo sourceFile in sources)
            {
                FileInfo destinationFile = new FileInfo(Path.Combine(destination.FullName, sourceFile.Name));
                long destinationChanged = destinationFile.LastWriteTime.Ticks/LastWriteTimePrecision;
                long sourceChanged = sourceFile.LastWriteTime.Ticks/LastWriteTimePrecision;
                if (!smart || destinationChanged != sourceChanged)
                {
                    sourceFile.CopyTo(destinationFile.FullName, true);
                }
            }

            foreach (DirectoryInfo directoryInfo in source.GetDirectories())
            {
                Synchronize(directoryInfo, new DirectoryInfo(Path.Combine(destination.FullName, directoryInfo.Name)), smart);
            }
        }
		public virtual void OnMerge(MergeEvent @event)
		{
			EventCache copyCache = new EventCache();
			
			OnMerge(@event, copyCache);
			
			// TODO: iteratively get transient entities and retry merge until one of the following conditions:
			//   1) transientCopyCache.size() == 0
			//   2) transientCopyCache.size() is not decreasing and copyCache.size() is not increasing
			
			// TODO: find out if retrying can add entities to copyCache (don't think it can...)
			// For now, just retry once; throw TransientObjectException if there are still any transient entities
			
			IDictionary transientCopyCache = this.GetTransientCopyCache(@event, copyCache);
			
			if (transientCopyCache.Count > 0)
			{
				RetryMergeTransientEntities(@event, transientCopyCache, copyCache);
				
				// find any entities that are still transient after retry
				transientCopyCache = this.GetTransientCopyCache(@event, copyCache);
				
				if (transientCopyCache.Count > 0)
				{
					IESI.ISet<string> transientEntityNames = new IESI.HashedSet<string>();
					
					foreach (object transientEntity in transientCopyCache.Keys)
					{
						string transientEntityName = @event.Session.GuessEntityName(transientEntity);
						
						transientEntityNames.Add(transientEntityName);
						
						log.InfoFormat(
							"transient instance could not be processed by merge: {0} [{1}]",
							transientEntityName,
							transientEntity.ToString());
					}
					
					throw new TransientObjectException("one or more objects is an unsaved transient instance - save transient instance(s) before merging: " + transientEntityNames);
				}
			}

			copyCache.Clear();
			copyCache = null;
		}
		private static IESI.ISet<string> GetReservedWords(Dialect.Dialect dialect, IConnectionHelper connectionHelper)
		{
			IESI.ISet<string> reservedDb = new IESI.HashedSet<string>();
			connectionHelper.Prepare();
			try
			{
				var metaData = dialect.GetDataBaseSchema(connectionHelper.Connection);
				foreach (var rw in metaData.GetReservedWords())
				{
					reservedDb.Add(rw.ToLowerInvariant());
				}
			}
			finally
			{
				connectionHelper.Release();
			}
			return reservedDb;
		}
		public IList TransformList(IList list)
		{
			IList result = (IList)Activator.CreateInstance(list.GetType());
			IESI.ISet<Identity> distinct = new IESI.HashedSet<Identity>();

			for (int i = 0; i < list.Count; i++)
			{
				object entity = list[i];
				if (distinct.Add(new Identity(entity)))
				{
					result.Add(entity);
				}
			}

			if (log.IsDebugEnabled)
			{
				log.Debug(string.Format("transformed: {0} rows to: {1} distinct results",
				                        list.Count, result.Count));
			}
			return result;
		}
		protected internal virtual SqlString GenerateLazySelectString()
		{
			if (!entityMetamodel.HasLazyProperties)
				return null;

			IESI.HashedSet<int> tableNumbers = new IESI.HashedSet<int>();
			List<int> columnNumbers = new List<int>();
			List<int> formulaNumbers = new List<int>();
			for (int i = 0; i < lazyPropertyNames.Length; i++)
			{
				// all this only really needs to consider properties
				// of this class, not its subclasses, but since we
				// are reusing code used for sequential selects, we
				// use the subclass closure
				int propertyNumber = GetSubclassPropertyIndex(lazyPropertyNames[i]);

				int tableNumber = GetSubclassPropertyTableNumber(propertyNumber);
				tableNumbers.Add(tableNumber);

				int[] colNumbers = subclassPropertyColumnNumberClosure[propertyNumber];
				for (int j = 0; j < colNumbers.Length; j++)
				{
					if (colNumbers[j] != -1)
					{
						columnNumbers.Add(colNumbers[j]);
					}
				}
				int[] formNumbers = subclassPropertyFormulaNumberClosure[propertyNumber];
				for (int j = 0; j < formNumbers.Length; j++)
				{
					if (formNumbers[j] != -1)
					{
						formulaNumbers.Add(formNumbers[j]);
					}
				}
			}

			if (columnNumbers.Count == 0 && formulaNumbers.Count == 0)
			{
				// only one-to-one is lazy fetched
				return null;
			}

			return RenderSelect(ArrayHelper.ToIntArray(tableNumbers), columnNumbers.ToArray(), formulaNumbers.ToArray());
		}
		protected string GenerateSubquery(PersistentClass model, IMapping mapping)
		{
			Dialect.Dialect dialect = Factory.Dialect;
			Settings settings = Factory.Settings;

			if (!model.HasSubclasses)
			{
				return model.Table.GetQualifiedName(dialect, settings.DefaultCatalogName, settings.DefaultSchemaName);
			}

			IESI.HashedSet<Column> columns = new IESI.HashedSet<Column>();
			foreach (Table table in model.SubclassTableClosureIterator)
			{
				if (!table.IsAbstractUnionTable)
				{
					foreach (Column column in table.ColumnIterator)
						columns.Add(column);
				}
			}

			StringBuilder buf = new StringBuilder().Append("( ");
			IEnumerable<PersistentClass> siter =
				new JoinedEnumerable<PersistentClass>(new SingletonEnumerable<PersistentClass>(model),
				                                      new SafetyEnumerable<PersistentClass>(model.SubclassIterator));

			foreach (PersistentClass clazz in siter)
			{
				Table table = clazz.Table;
				if (!table.IsAbstractUnionTable)
				{
					buf.Append("select ");
					foreach (Column col in columns)
					{
						if (!table.ContainsColumn(col))
						{
							SqlType sqlType = col.GetSqlTypeCode(mapping);
							buf.Append(dialect.GetSelectClauseNullString(sqlType)).Append(" as ");
						}
						buf.Append(col.Name);
						buf.Append(StringHelper.CommaSpace);
					}
					buf.Append(clazz.SubclassId).Append(" as clazz_");
					buf.Append(" from ").Append(table.GetQualifiedName(dialect, settings.DefaultCatalogName, settings.DefaultSchemaName));
					buf.Append(" union ");
					if (dialect.SupportsUnionAll)
						buf.Append("all ");
				}
			}

			if (buf.Length > 2)
			{
				//chop the last union (all)
				buf.Length -= (dialect.SupportsUnionAll ? 11 : 7); //" union " : "all "
			}

			return buf.Append(" )").ToString();
		}
		public UnionSubclassEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, 
			ISessionFactoryImplementor factory, IMapping mapping):base(persistentClass, cache, factory)
		{
			if (IdentifierGenerator is IdentityGenerator)
			{
				throw new MappingException("Cannot use identity column key generation with <union-subclass> mapping for: " + EntityName);
			}

			// TABLE

			tableName =
				persistentClass.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName,
				                                       factory.Settings.DefaultSchemaName);

			#region Custom SQL

			SqlString sql;
			bool callable;
			ExecuteUpdateResultCheckStyle checkStyle;

			sql = persistentClass.CustomSQLInsert;
			callable = sql != null && persistentClass.IsCustomInsertCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLInsertCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLInsert = new SqlString[] { sql };
			insertCallable = new bool[] { callable };
			insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			sql = persistentClass.CustomSQLUpdate;
			callable = sql != null && persistentClass.IsCustomUpdateCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLUpdateCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLUpdate = new SqlString[] { sql };
			updateCallable = new bool[] { callable };
			updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			sql = persistentClass.CustomSQLDelete;
			callable = sql != null && persistentClass.IsCustomDeleteCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLDeleteCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLDelete = new SqlString[] { sql };
			deleteCallable = new bool[] { callable };
			deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			#endregion

			discriminatorValue = persistentClass.SubclassId;
			discriminatorSQLValue = persistentClass.SubclassId.ToString();

			#region PROPERTIES

			int subclassSpan = persistentClass.SubclassSpan + 1;
			subclassClosure = new string[subclassSpan];
			subclassClosure[0] = EntityName;

			#endregion

			#region SUBCLASSES

			subclassByDiscriminatorValue[persistentClass.SubclassId] = persistentClass.EntityName;
			if (persistentClass.IsPolymorphic)
			{
				int k = 1;
				foreach (Subclass sc in persistentClass.SubclassIterator)
				{
					subclassClosure[k++] = sc.EntityName;
					subclassByDiscriminatorValue[sc.SubclassId] = sc.EntityName;
				}
			}

			#endregion

			#region SPACES
			//TODO: i'm not sure, but perhaps we should exclude abstract denormalized tables?

			int spacesSize = 1 + persistentClass.SynchronizedTables.Count;
			spaces = new string[spacesSize];
			spaces[0] = tableName;
			IEnumerator<string> iSyncTab = persistentClass.SynchronizedTables.GetEnumerator();
			for (int i = 1; i < spacesSize; i++)
			{
				iSyncTab.MoveNext();
				spaces[i] = iSyncTab.Current;
			}

			IESI.HashedSet<string> subclassTables = new IESI.HashedSet<string>();
			foreach (Table table in persistentClass.SubclassTableClosureIterator)
			{
				subclassTables.Add(
					table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName));
			}
			subclassSpaces = new string[subclassTables.Count];
			subclassTables.CopyTo(subclassSpaces, 0);

			subquery = GenerateSubquery(persistentClass, mapping);

			if (IsMultiTable)
			{
				int idColumnSpan = IdentifierColumnSpan;
				List<string> tableNames = new List<string>();
				List<string[]> keyColumns = new List<string[]>();
				if (!IsAbstract)
				{
					tableNames.Add(tableName);
					keyColumns.Add(IdentifierColumnNames);
				}
				foreach (Table tab in persistentClass.SubclassTableClosureIterator)
				{
					if (!tab.IsAbstractUnionTable)
					{
						string _tableName =
							tab.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
						tableNames.Add(_tableName);

						List<string> key = new List<string>(idColumnSpan);
						foreach (Column column in tab.PrimaryKey.ColumnIterator)
							key.Add(column.GetQuotedName(factory.Dialect));

						keyColumns.Add(key.ToArray());
					}					
				}

				constraintOrderedTableNames = tableNames.ToArray();
				constraintOrderedKeyColumnNames = keyColumns.ToArray();
			}
			else
			{
				constraintOrderedTableNames = new string[] { tableName };
				constraintOrderedKeyColumnNames = new string[][] { IdentifierColumnNames };
			}
			#endregion

			InitLockers();

			InitSubclassPropertyAliasesMap(persistentClass);

			PostConstruct(mapping);
		}
示例#11
0
		public virtual void Resolve()
		{
			// Make sure that all from elements registered with this FROM clause are actually in the AST.
			var iter = (new ASTIterator(GetFirstChild())).GetEnumerator();
			var childrenInTree = new IESI.HashedSet<IASTNode>();
			while (iter.MoveNext())
			{
				childrenInTree.Add(iter.Current);
			}
			foreach (var fromElement in _fromElements)
			{
				if (!childrenInTree.Contains(fromElement))
				{
					throw new SemanticException("Element not in AST: " + fromElement);
				}
			}
		}
		private void CheckPropertyDuplication()
		{
			IESI.HashedSet<string> names = new IESI.HashedSet<string>();
			foreach (Property prop in PropertyIterator)
			{
				if (!names.Add(prop.Name))
					throw new MappingException("Duplicate property mapping of " + prop.Name + " found in " + EntityName);
			}
		}
		public void AutoQuoteTableAndColumnsAtStratupIncludeKeyWordsImport()
		{
			var reservedDb = new IESI.HashedSet<string>();
			var configuration = TestConfigurationHelper.GetDefaultConfiguration();
			var dialect = Dialect.Dialect.GetDialect(configuration.Properties);
			var connectionHelper = new ManagedProviderConnectionHelper(configuration.Properties);
			connectionHelper.Prepare();
			try
			{
				var metaData = dialect.GetDataBaseSchema(connectionHelper.Connection);
				foreach (var rw in metaData.GetReservedWords())
				{
					reservedDb.Add(rw.ToLowerInvariant());
				}
			}
			finally
			{
				connectionHelper.Release();
			}

			configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote");
			configuration.AddResource("NHibernate.Test.Tools.hbm2ddl.SchemaMetadataUpdaterTest.HeavyEntity.hbm.xml",
																GetType().Assembly);
			var sf = (ISessionFactoryImplementor)configuration.BuildSessionFactory();
			var match = reservedDb.Intersect(sf.Dialect.Keywords);
			Assert.That(match, Is.EquivalentTo(reservedDb));
		}
        public virtual IESI.ISet<string> GetReservedWords()
		{
			var result = new IESI.HashedSet<string>();
			DataTable dtReservedWords = connection.GetSchema(DbMetaDataCollectionNames.ReservedWords);
			foreach (DataRow row in dtReservedWords.Rows)
			{
				result.Add(row["ReservedWord"].ToString());
			}
			return result;
		}
		private IDictionary<string, string[]> BindPropertyResults(string alias, HbmReturnDiscriminator discriminatorSchema,
			HbmReturnProperty[] returnProperties, PersistentClass pc)
		{
			Dictionary<string, string[]> propertyresults = new Dictionary<string, string[]>();
			// maybe a concrete SQLpropertyresult type, but Map is exactly what is required at the moment

			if (discriminatorSchema != null)
			{
				propertyresults["class"] = GetResultColumns(discriminatorSchema).ToArray();
			}

			List<HbmReturnProperty> properties = new List<HbmReturnProperty>();
			List<string> propertyNames = new List<string>();

			foreach (HbmReturnProperty returnPropertySchema in returnProperties ?? new HbmReturnProperty[0])
			{
				string name = returnPropertySchema.name;
				if (pc == null || name.IndexOf('.') == -1)
				{
					//if dotted and not load-collection nor return-join
					//regular property
					properties.Add(returnPropertySchema);
					propertyNames.Add(name);
				}
				else
				{
					// Reorder properties
					// 1. get the parent property
					// 2. list all the properties following the expected one in the parent property
					// 3. calculate the lowest index and insert the property

					int dotIndex = name.LastIndexOf('.');
					string reducedName = name.Substring(0, dotIndex);
					IValue value = pc.GetRecursiveProperty(reducedName).Value;
					IEnumerable<Mapping.Property> parentPropIter;
					if (value is Component)
					{
						Component comp = (Component) value;
						parentPropIter = comp.PropertyIterator;
					}
					else if (value is ToOne)
					{
						ToOne toOne = (ToOne) value;
						PersistentClass referencedPc = mappings.GetClass(toOne.ReferencedEntityName);
						if (toOne.ReferencedPropertyName != null)
							try
							{
								parentPropIter =
									((Component) referencedPc.GetRecursiveProperty(toOne.ReferencedPropertyName).Value).PropertyIterator;
							}
							catch (InvalidCastException e)
							{
								throw new MappingException("dotted notation reference neither a component nor a many/one to one", e);
							}
						else
							try
							{
								parentPropIter = ((Component) referencedPc.IdentifierProperty.Value).PropertyIterator;
							}
							catch (InvalidCastException e)
							{
								throw new MappingException("dotted notation reference neither a component nor a many/one to one", e);
							}
					}
					else
						throw new MappingException("dotted notation reference neither a component nor a many/one to one");
					bool hasFollowers = false;
					List<string> followers = new List<string>();
					foreach (Mapping.Property prop in parentPropIter)
					{
						string currentPropertyName = prop.Name;
						string currentName = reducedName + '.' + currentPropertyName;
						if (hasFollowers)
							followers.Add(currentName);
						if (name.Equals(currentName))
							hasFollowers = true;
					}

					int index = propertyNames.Count;
					int followersSize = followers.Count;
					for (int loop = 0; loop < followersSize; loop++)
					{
						string follower = followers[loop];
						int currentIndex = GetIndexOfFirstMatchingProperty(propertyNames, follower);
						index = currentIndex != -1 && currentIndex < index ? currentIndex : index;
					}
					propertyNames.Insert(index, name);
					properties.Insert(index, returnPropertySchema);
				}
			}

			IESI.ISet<string> uniqueReturnProperty = new IESI.HashedSet<string>();
			foreach (HbmReturnProperty returnPropertySchema in properties)
			{
				string name = returnPropertySchema.name;
				if ("class".Equals(name))
					throw new MappingException(
						"class is not a valid property name to use in a <return-property>, use <return-discriminator> instead"
						);
				//TODO: validate existing of property with the chosen name. (secondpass )
				List<string> allResultColumns = GetResultColumns(returnPropertySchema);

				if (allResultColumns.Count == 0)
					throw new MappingException(
						"return-property for alias " + alias +
							" must specify at least one column or return-column name"
						);
				if (uniqueReturnProperty.Contains(name))
					throw new MappingException(
						"duplicate return-property for property " + name +
							" on alias " + alias
						);
				uniqueReturnProperty.Add(name);

				// the issue here is that for <return-join/> representing an entity collection,
				// the collection element values (the property values of the associated entity)
				// are represented as 'element.{propertyname}'.  Thus the StringHelper.root()
				// here puts everything under 'element' (which additionally has significant
				// meaning).  Probably what we need to do is to something like this instead:
				//      String root = StringHelper.root( name );
				//      String key = root; // by default
				//      if ( !root.equals( name ) ) {
				//	        // we had a dot
				//          if ( !root.equals( alias ) {
				//              // the root does not apply to the specific alias
				//              if ( "elements".equals( root ) {
				//                  // we specifically have a <return-join/> representing an entity collection
				//                  // and this <return-property/> is one of that entity's properties
				//                  key = name;
				//              }
				//          }
				//      }
				// but I am not clear enough on the intended purpose of this code block, especially
				// in relation to the "Reorder properties" code block above... 
				//			String key = StringHelper.root( name );
				string key = name;
				string[] intermediateResults;
				if (!propertyresults.TryGetValue(key,out intermediateResults))
					propertyresults[key] = allResultColumns.ToArray();
				else
					ArrayHelper.AddAll(intermediateResults, allResultColumns); // TODO: intermediateResults not used after this
			}

			Dictionary<string, string[]> newPropertyResults = new Dictionary<string, string[]>();

			foreach (KeyValuePair<string, string[]> entry in propertyresults)
			{
				newPropertyResults[entry.Key] = entry.Value;
			}
			return newPropertyResults.Count == 0 ? (IDictionary<string, string[]>)new CollectionHelper.EmptyMapClass<string, string[]>() : newPropertyResults;
		}
		public AssignmentSpecification(IASTNode eq, IQueryable persister)
		{
			if (eq.Type != HqlSqlWalker.EQ)
			{
				throw new QueryException("assignment in set-clause not associated with equals");
			}

			_eq = eq;
			_factory = persister.Factory;

			// Needed to bump this up to DotNode, because that is the only thing which currently
			// knows about the property-ref path in the correct format; it is either this, or
			// recurse over the DotNodes constructing the property path just like DotNode does
			// internally
			DotNode lhs;
			try
			{
				lhs = (DotNode)eq.GetFirstChild();
			}
			catch (InvalidCastException e)
			{
				throw new QueryException(
					string.Format("Left side of assigment should be a case sensitive property or a field (depending on mapping); found '{0}'", eq.GetFirstChild()), e);
			}
			var rhs = (SqlNode)lhs.NextSibling;

			ValidateLhs(lhs);

			string propertyPath = lhs.PropertyPath;
			var temp = new IESI.HashedSet<string>();
			// yuck!
			var usep = persister as UnionSubclassEntityPersister;
			if (usep!=null)
			{
				temp.AddAll(persister.ConstraintOrderedTableNameClosure);
			}
			else
			{
				temp.Add(persister.GetSubclassTableName(persister.GetSubclassPropertyTableNumber(propertyPath)));
			}
			_tableNames = new IESI.ImmutableSet<string>(temp);

			if (rhs == null)
			{
				_hqlParameters = new IParameterSpecification[0];
			}
			else if (IsParam(rhs))
			{
				_hqlParameters = new[] { ((ParameterNode)rhs).HqlParameterSpecification };
			}
			else
			{
				var parameterList = ASTUtil.CollectChildren(rhs, IsParam);
				_hqlParameters = new IParameterSpecification[parameterList.Count];
				int i = 0;
				foreach (ParameterNode parameterNode in parameterList)
				{
					_hqlParameters[i++] = parameterNode.HqlParameterSpecification;
				}
			}
		}