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