[ 
https://issues.apache.org/jira/browse/IBATISNET-17?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Gilles Bayon closed IBATISNET-17.
---------------------------------

       Resolution: Fixed
    Fix Version/s: DataMapper 1.6.2
         Assignee: Gilles Bayon

close old issue

> Different bugs using Complex Properties
> ---------------------------------------
>
>                 Key: IBATISNET-17
>                 URL: https://issues.apache.org/jira/browse/IBATISNET-17
>             Project: iBatis for .NET
>          Issue Type: Bug
>            Reporter: Henrik Uffe Jensen
>            Assignee: Gilles Bayon
>             Fix For: DataMapper 1.6.2
>
>
> I was trying to use some complex properties in resultmaps and parametermaps 
> but ran into some problems.
> The development guide section 3.4.7 (Example 34) is showing complex 
> properties the way I also tried to use them. I explain the problems using the 
> reference to this 'product', 'catalog' object example. 
> Found out that the problems all related to the fact that the seperat 
> Reflectioninfo is created and cached for each object containing only their 
> local memberproperties, but different places in the code doesn't handle this. 
> So with our example two ReflectionInfo's are created. One for 'product' 
> containing the 'id' and 'description' properties, and one for 'catalog' 
> containing 'id' and 'description' 
> * My first problem was that I couldn't save an object with a complex property 
> containing an enum. (Well no enums in the mentioned example but anyway...)
> Found out that this was due to the enum handling in 
> IBatisNet.DataMapper.Configuration.ParameterMapping.GetValueOfProperty. 
> The following line of code will try to get the ReflectionInfo from the source 
> object type and get the propertyinfo using propertyname. But with our comples 
> property example we acually get the 'Product' instance of the ReflectionInfo 
> also when we want the 'Catalog' RefelctionInfo. Further more the propertyName 
> is 'category.id' and only the 'id' part is present in the reflectioninfo.
> PropertyInfo propertyInfo =  
> ReflectionInfo.GetInstance(source.GetType()).GetGetter( propertyName );
> I added two new methods to IBatisNet.Common.Utilities.Objects.ObjectProbe, 
> which can help find the correct type and propertyname for both normal and 
> complex properties
> /// <summary>
> /// Return the type of the object that the property belongs to. 
> /// </summary>
> /// <param name="obj">The Object on which to invoke the specified 
> property.</param>
> /// <param name="propertyName">The name of the property.</param>
> /// <returns>An object type of the object the property belongs to.</returns>
> public static Type GetObjectType(object obj, string propertyName) 
> {
>       if (propertyName.IndexOf('.') > -1) 
>       {
>               StringTokenizer parser = new StringTokenizer(propertyName, ".");
>               IEnumerator enumerator = parser.GetEnumerator();
>               object value = obj;
>               string token = null;
>               Type type = null;
>               while (enumerator.MoveNext()) 
>               {
>                       token = (string)enumerator.Current;
>                       value = GetProperty(value, token);
>                       if (value != null && value.GetType().IsClass)
>                       {
>                               type = value.GetType();
>                       }
>                       if (value == null) 
>                       {
>                               break;
>                       }
>               }
>               return type;
>       } 
>       else 
>       {
>               return obj.GetType();
>       }
> }
>               
> /// <summary>
> /// Return the name of the property used in property maps
> /// </summary>
> /// <param name="propertyName">The name of the property.</param>
> /// <returns>An string representing the name of the property used in property 
> maps.</returns>
> public static string GetPropertyNameForPropertyMap(string propertyName) 
> {
>       if (propertyName.IndexOf('.') > -1) 
>       {
>               string[] arr = propertyName.Split('.');
>               return arr[arr.Length - 1];
>       } 
>       else 
>       {
>               return propertyName;
>       }
> }
> I then changed the code in 
> IBatisNet.DataMapper.Configuration.ParameterMapping.GetValueOfProperty to the 
> following. Using the new methods to get the correct type and propertyname. 
> After that I could save a complex property containing an enum
>       #region Enum case
>                               
>       // HUJ : Get type and propertyname to use for ReflectionInfo and 
> PropertyMap cache
>       Type type = ObjectProbe.GetObjectType(source, propertyName);
>       string propertyNameInMap = 
> ObjectProbe.GetPropertyNameForPropertyMap(propertyName);
>       // HUJ : Use above type and propertyname in order to work correct with 
> complex properties
>       PropertyInfo propertyInfo =  
> ReflectionInfo.GetInstance(type).GetGetter( propertyNameInMap );
>         // PropertyInfo propertyInfo =  
> ReflectionInfo.GetInstance(source.GetType()).GetGetter( propertyName );
> * Next problem then was that I could not use Complex properties at all when 
> trying to get data from the database. This is actually exactly the example 
> mentioned. 
> Found out that this was due to the enum handling in 
> IBatisNet.DataMapper.Configuration.ResultMapping.SetValueOfProperty and in 
> IBatis.DataMapper.Configuration.ResultMapping.GetProperties
> In 'GetProperties' there are the same problem as mentioned before so I solved 
> it again by using the two new methods in ObjectProbe. A little extra thing is 
> that in order to get the type I create an instance of the result object. 
> There are probably a nicer way to do this but I works.
> /// <summary>
> /// Get the result properties from the xmNode.
> /// </summary>
> /// <param name="node">An xmlNode.</param>
> private void GetProperties(XmlNode node)
> {
>       XmlSerializer serializer = null;
>       ResultProperty property = null;
>       /// HUJ : Create instance of result for use with 
> ObjectProbe.GetObjectType
>       object value = CreateInstanceOfResult();
>       serializer = new XmlSerializer(typeof(ResultProperty));
>       foreach ( XmlNode resultNode in node.SelectNodes("result") )
>       {
>               property = (ResultProperty) serializer.Deserialize(new 
> XmlNodeReader(resultNode));
>                       
>               PropertyInfo propertyInfo = null;
>               if ( property.PropertyName != "value" && 
> !typeof(IDictionary).IsAssignableFrom(_class) )
>               {
>                       // HUJ : Get correct type and propertyname for use in 
> ReflectionInfo and PropertyMap cache
>                       Type type = ObjectProbe.GetObjectType( value, 
> property.PropertyName );
>                       string propertyNameInMap = 
> ObjectProbe.GetPropertyNameForPropertyMap( property.PropertyName );
>                        // HUJ : Use aboe type and propertyname
>                       propertyInfo = 
> ReflectionInfo.GetInstance(type).GetSetter( propertyNameInMap );
>                       //propertyInfo = 
> ReflectionInfo.GetInstance(_class).GetSetter( property.PropertyName );
>               }
>               property.Initialize( propertyInfo );
>               this.AddResultPropery( property  );
>       }
> }
> In 'SetValueOfProperty' the problem was that the value of a complex 
> property's property is trying to be set on the main object. So property 
> 'description' on object 'category' would actually be set on the 'product' 
> object. This "works" with example 34 but that's only because 'id' and 
> 'description' is present on both the 'product' and the 'catagory' object.
> Well what I do now is to check if the ReflectedType is the same as the main 
> object (_class) and if not then user another new method from ObjectProbe to 
> get the reflected object.
> // HUJ : When using complex properties we need to get and use the reflected 
> object
> object reflectedObject = null;
> if (property.PropertyInfo.ReflectedType != _class)
> {
>         reflectedObject = ObjectProbe.GetReflectedObject(target, 
> property.PropertyName);
> }
> else
> {
>       reflectedObject = target;
> }
> property.PropertyInfo.SetValue( reflectedObject, dataBaseValue, null );
> //property.PropertyInfo.SetValue( target, dataBaseValue, null );
> Here is the new method in ObjectProbe
> /// <summary>
> /// Return the type of the object that the property belongs to. 
> /// </summary>
> /// <param name="obj">The Object on which to invoke the specified 
> property.</param>
> /// <param name="propertyName">The name of the property.</param>
> /// <returns>An object type of the object the property belongs to.</returns>
> public static object GetReflectedObject(object obj, string propertyName) 
> {
>       if (propertyName.IndexOf('.') > -1) 
>       {
>               StringTokenizer parser = new StringTokenizer(propertyName, ".");
>               IEnumerator enumerator = parser.GetEnumerator();
>               object value = obj;
>               string token = null;
>               object reflectedObject = null;
>               while (enumerator.MoveNext()) 
>               {
>                       token = (string)enumerator.Current;
>                       value = GetProperty(value, token);
>                       if (value != null && value.GetType().IsClass)
>                       {
>                               reflectedObject = value;
>                       }
>                       if (value == null) 
>                       {
>                               break;
>                       }
>               }
>               return reflectedObject;
>       } 
>       else 
>       {
>               return obj;
>       }
> }
> Well all of the above code works for me now, but I haven't tested it 
> thorougly with all kinds of configurations and neither have I looked into if 
> things could be refactored and done in a nicer way. 
> BTW you mentioned something about that I could take a look in SVN last time I 
> reported a bug. But where are your SVN located? I can't find it on 
> svn.apache.org ?
> Best regards
> Henrik Uffe Jensen

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to