-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: GetSetHelperFactory - incorrect generated code for ValueType
PostPosted: Fri Jan 20, 2006 5:33 am 
Newbie

Joined: Fri Jan 20, 2006 5:15 am
Posts: 4
Hi, all!

Tonight I’ve found “interest” bug when played with NHibernate 1.0.1. Following situation was appeared:

I’ve developed following component class (in terms of NHibernate):

Code:
public struct Money
{
   //...

   public decimal Amount
   {
      get { return _amount; }
      set { _amount = value; }
   }

   //...


And used it like following:
Code:
public class Account : DomainEntity
{
//...      
public Money Balance
      {
         get { return _balance; }
         set { _balance = value; }
      }
//...


Following mapping enabled:
Code:
<hibernate-mapping >
   <class ...>
      ...
      <component name="Balance">
         <property name="Amount" />
      </component>
      ...
   </class>
</hibernate-mapping>


And when I’ve performed simple list loading, the Amount property always was initialized with zero.
I’ve started to researching sources and have found this line:

this.getset.SetPropertyValues(component, values);

in the class ComponentType in method SetPropertyValues( object component, object[ ] values ) set target property (Amount) to nothing.

And later I’ve found the reason of this strange behavior:

Code has generated by the class GetSetHelperFactory in the method GenerateCode() do not make a differences between the value or reference type of mapped class.

My modifications which solve this bug you can see below:
Code:
       private string GenerateCode()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(header);
            sb.AppendFormat(classDef, mappedClass.FullName.Replace('.', '_').Replace("+", "__"));

         string componentAccessor = null;

         if (!mappedClass.IsValueType)
         {
            componentAccessor = "t";
            sb.AppendFormat(startSetMethod, mappedClass.FullName.Replace('+', '.'));
         }
         else
            componentAccessor = String.Format("(({0})obj)", mappedClass.FullName.Replace('+', '.'));

            for (int i = 0; i < setters.Length; i++)
            {
                ISetter setter = setters[i];
                if (setter is BasicSetter && IsPublic(setter.PropertyName))
                {
                    if (setter.Property.PropertyType.IsValueType)
                    {
                        sb.AppendFormat(
                            "  {3}.{0} = values[{2}] == null ? new {1}() : ({1})values[{2}];\n",
                            setter.PropertyName,
                            setter.Property.PropertyType.FullName.Replace('+', '.'),
                            i, componentAccessor );
                    }
                    else
                    {
                        sb.AppendFormat("  {3}.{0} = ({1})values[{2}];\n",
                            setter.PropertyName,
                            setter.Property.PropertyType.FullName.Replace('+', '.'),
                     i, componentAccessor);
                    }


Regards


Top
 Profile  
 
 Post subject: Yes indeed!!!
PostPosted: Fri Jan 20, 2006 6:55 am 
Regular
Regular

Joined: Tue Jan 03, 2006 7:21 am
Posts: 85
I just tried the same example and the balance is indeed initialized to zero....
This works correctly if the Money is declared as a class instead of struct. But if it is struct the Amount member is set to zero....


Top
 Profile  
 
 Post subject: Re: Yes indeed!!!
PostPosted: Fri Jan 20, 2006 8:03 am 
Newbie

Joined: Fri Jan 20, 2006 5:15 am
Posts: 4
samujob wrote:
I just tried the same example and the balance is indeed initialized to zero....
This works correctly if the Money is declared as a class instead of struct. But if it is struct the Amount member is set to zero....


Sure! I've found this problem too and 'invent' the solution.

Let me know, is this problem fixed in the 1.0.2 release? In the release notes is this line:

* [NH-505] - Reflection optimizer does not work with structures

Is this a same problem with I descibed above?


Top
 Profile  
 
 Post subject: Found another solution
PostPosted: Fri Jan 20, 2006 8:18 am 
Regular
Regular

Joined: Tue Jan 03, 2006 7:21 am
Posts: 85
I do not think NH[505] deals with this scenario.

The problem here is that the generated code is changing a Struct within the method and Struct is passed by Value, so any changes made within the method is not visible in the copy that was passed to it.
The solution is to use ref keyword. I found another way to fix this:

I added a new variable startSetMethod1 same as startSetMethod but the signature uses ref and exact class is passed instead of Object
const string startSetMethod1 =
"public void SetPropertyValues(ref {0} obj, object[] values) {{\n" +
" {0} t = ({0})obj;\n";

In GenerateCode method I modified the generation of the startmethod fragment to use my new variable is the class is a value type:
if (!mappedClass.IsValueType)
sb.AppendFormat(startSetMethod, mappedClass.FullName.Replace('+', '.'));
else
sb.AppendFormat(startSetMethod1, mappedClass.FullName.Replace('+', '.'));

Before the end of the method I set obj = t if the class is a value type (this modifies the input struct values as it is passed by ref)
if (mappedClass.IsValueType)
sb.Append("obj=t;\n");

That does it... Now I can see it working OK....


Top
 Profile  
 
 Post subject: Re: Found another solution
PostPosted: Fri Jan 20, 2006 8:29 am 
Newbie

Joined: Fri Jan 20, 2006 5:15 am
Posts: 4
Ok, I'm happy that this problem and their solution is known to team (or not?)...

And tell me anybody from the NH team, will this problem be fixed in next build? :)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 20, 2006 9:14 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Should be fixed in 1.0.2 already.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 20, 2006 9:24 am 
Newbie

Joined: Fri Jan 20, 2006 5:15 am
Posts: 4
sergey wrote:
Should be fixed in 1.0.2 already.


Ok, thanks!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.