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);
				}
			}

			var uniqueReturnProperty = new HashSet<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
				{
					throw new NotImplementedException();
					// 2013-02-24: In 89994bc113e1bb35bf6bcd0b7408d08340bfbccd, 2008-05-29, the intermediateResults
					// variable was changed from ArrayList to string[]. The following code line was there before.
					// Since an array cannot be modified, it seems this code line has never been hit since then.
					// While working on NH-3345, I'm adding an ambigous overload for AddAll(), and I don't want to
					// try to understand this code right now, so comment it out instead. /Oskar
					//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;
		}
		private static List<string> GetResultColumns(HbmReturnProperty returnPropertySchema)
		{
			List<string> allResultColumns = new List<string>();
			String column = Unquote(returnPropertySchema.column);

			if (column != null)
				allResultColumns.Add(column);

			foreach (HbmReturnColumn returnColumnSchema in returnPropertySchema.returncolumn ?? new HbmReturnColumn[0])
				allResultColumns.Add(Unquote(returnColumnSchema.name));

			return allResultColumns;
		}
Ejemplo n.º 3
0
        private IDictionary BindPropertyResults(string alias, HbmReturnDiscriminator discriminatorSchema,
            HbmReturnProperty[] returnProperties, PersistentClass pc)
        {
            IDictionary propertyresults = new Hashtable();
            // maybe a concrete SQLpropertyresult type, but Map is exactly what is required at the moment

            if (discriminatorSchema != null)
            {
                ArrayList resultColumns = GetResultColumns(discriminatorSchema);
                propertyresults["class"] = ArrayHelper.ToStringArray(resultColumns);
            }

            IList properties = new ArrayList();
            IList propertyNames = new ArrayList();

            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;
                    IList followers = new ArrayList();
                    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 = (String) followers[loop];
                        int currentIndex = GetIndexOfFirstMatchingProperty(propertyNames, follower);
                        index = currentIndex != -1 && currentIndex < index ? currentIndex : index;
                    }
                    propertyNames.Insert(index, name);
                    properties.Insert(index, returnPropertySchema);
                }
            }

            ISet uniqueReturnProperty = new HashedSet();
            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 )
                ArrayList 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;
                ArrayList intermediateResults = (ArrayList) propertyresults[key];
                if (intermediateResults == null)
                    propertyresults[key] = allResultColumns;
                else
                    ArrayHelper.AddAll(intermediateResults, allResultColumns);
            }

            IDictionary newPropertyResults = new Hashtable();

            foreach (DictionaryEntry entry in propertyresults)
                if (entry.Value is ArrayList)
                {
                    ArrayList list = (ArrayList) entry.Value;
                    newPropertyResults[entry.Key] = ArrayHelper.ToStringArray(list);
                }
                else
                    newPropertyResults[entry.Key] = entry.Value;
            return newPropertyResults.Count == 0 ? CollectionHelper.EmptyMap : newPropertyResults;
        }