[
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.