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.  [ 8 posts ] 
Author Message
 Post subject: Problem w/ proxied class
PostPosted: Mon Sep 19, 2005 6:32 pm 
Newbie

Joined: Mon Sep 19, 2005 6:08 pm
Posts: 4
I got a strange behavior and I don't know how to find the problem. I've a proxied class (all public members virtual), which works fine except at the very start of the session, when I request for a list of all the objects of the proxied class, it returns two objects: one is the actual concrete object, and the other is the proxy (I have a screentshot of my debug window to show, but don't know how can I attach to this post). When I attempt to bind the list to datagrid, it throws exception because one of the objects is not of expected type. How can this happen?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 20, 2005 9:31 am 
Contributor
Contributor

Joined: Thu May 12, 2005 9:45 am
Posts: 593
Location: nhibernate.org
Can you provide your mapping files and the query you are executing?

_________________
Pierre Henri Kuaté.
Get NHibernate in Action Now!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 20, 2005 2:08 pm 
Newbie

Joined: Mon Sep 19, 2005 6:08 pm
Posts: 4
Here's my execution code:

public IList GetSampleSchedTypes()
{
IList result = null;
try
{
int orgId = this.boSession.clientId;
string hql = String.Format(@"from SampleSchedType st where st.ownerOrg.id={0} order by name", orgId);
result = this.boSession.hbSession.Find(hql);
}
catch (Exception ex)
{
this.logger.Error(ex.ToString());
}
return result;
}



Here's my mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="WaterTrax.WTX.WTXObjectModel.SampleScheduling.SampleSchedType, WTXObjectModel" table="tSampleSchedType" proxy="WaterTrax.WTX.WTXObjectModel.SampleScheduling.SampleSchedType, WTXObjectModel">

<id name="id" column="SampleSchedTypeID" unsaved-value="0">
<generator class="native" />
</id>

<many-to-one name="ownerOrg"
class="WaterTrax.WTX.WTXObjectModel.Organizations.Organization, WTXObjectModel"
column="OrgID"/>

<set name="sampleAnalyteGroups" inverse="true" cascade="all-delete-orphan" lazy="true">
<key column="SampleSchedTypeID"/>
<one-to-many class="WaterTrax.WTX.WTXObjectModel.SampleScheduling.SampleAnalyteGroup, WTXObjectModel"/>
</set>

<property name="name" column="Name" />
<property name="description" column="Description" />

</class>


</hibernate-mapping>





Here's my exception log:

Line 50: IList stypes = m_bostype.GetSampleSchedTypes();
Line 51: dgrdSampleTypes.DataSource = stypes;
Line 52: dgrdSampleTypes.DataBind();
Line 53: }
Line 54: #endregion


Source File: c:\watertrax\websolution\wtxsamplescheduling\sampletypelist.aspx.cs Line: 52

Stack Trace:


[TargetException: Object does not match target type.]
System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess) +0
System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean verifyAccess) +425
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +23
System.Reflection.MethodInfo.Invoke(Object obj, Object[] parameters) +17
System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component)

[TargetInvocationException: Property accessor 'name' on object 'WaterTrax.WTX.WTXObjectModel.SampleScheduling.SampleSchedType' threw the following exception:'Object does not match target type.']
System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component)
System.Web.UI.WebControls.BoundColumn.OnDataBindColumn(Object sender, EventArgs e)
System.Web.UI.Control.OnDataBinding(EventArgs e)
System.Web.UI.Control.DataBind()
System.Web.UI.Control.DataBind()
System.Web.UI.WebControls.DataGrid.CreateItem(Int32 itemIndex, Int32 dataSourceIndex, ListItemType itemType, Boolean dataBind, Object dataItem, DataGridColumn[] columns, TableRowCollection rows, PagedDataSource pagedDataSource)
System.Web.UI.WebControls.DataGrid.CreateControlHierarchy(Boolean useDataSource)
System.Web.UI.WebControls.BaseDataList.OnDataBinding(EventArgs e)
System.Web.UI.WebControls.BaseDataList.DataBind()
WaterTrax.WTX.Web.WTXSampleScheduling.SampleTypeList.LoadData() in c:\watertrax\websolution\wtxsamplescheduling\sampletypelist.aspx.cs:52
WaterTrax.WTX.Web.WTXSampleScheduling.SampleTypeList.Page_Load(Object sender, EventArgs e) in c:\watertrax\websolution\wtxsamplescheduling\sampletypelist.aspx.cs:61
System.Web.UI.Control.OnLoad(EventArgs e)
System.Web.UI.Control.LoadRecursive()
System.Web.UI.Page.ProcessRequestMain()


Thanks


Top
 Profile  
 
 Post subject: Any updates?
PostPosted: Tue Jan 23, 2007 12:21 am 
Newbie

Joined: Tue Jan 23, 2007 12:19 am
Posts: 1
Hi, I'm having the same problem. Did you find a solution for it?

Thank you,
Jerry


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 23, 2007 9:19 am 
Newbie

Joined: Mon Jun 12, 2006 1:06 pm
Posts: 3
[What are the odds that I'd happen upon this post just after it'd been re-awakened after so long? Anyway....]

I'm not sure this is entirely relevant to, or that I understand the initial problem (was it a proxy and a concrete class when only one entity should have been returned, or was it correct that two were returned?), but I found that:
Running a .Find("FROM ExampleEntity") - i.e. to retrieve a list of all entities of a (non-subclassed) type, returned some as concrete classes and some as proxies. [I definitely didn't want any proxies - I wanted all entity data pre-loaded since I was about to do a .Replicate.]
The reason, it seems, is to do with having loaded up some objects earlier in the session that were related to a particular ExampleEntity (which had therefore instantiated a proxy for it). In my result list, those entities that had already been proxied because of a lazy relationship returned proxies - and those that hadn't been proxied returned the concrete classes.
[Because I'm currently doing batch work, my solution was to clear the session before running the query - but I'm sure that won't be viable in a lot of cases.]
Anyway, hope that helps provide a starting point for someone....

Mike.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 23, 2007 5:33 pm 
Regular
Regular

Joined: Mon Mar 20, 2006 10:49 pm
Posts: 59
Some months ago, I found a web posting describing this situation (a list containing a mixture of object instances and proxies). I downloaded a wrapper class which proxies everything in the list, thus presenting a consistent type for the list items to the data binder. I've never tried it, but, for what it's worth, here is is:
Code:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

using Castle.DynamicProxy;
using Iesi.Collections.Generic;

namespace Monitor.MktgWorksite.BLL.NHibernateSupport
{
    public class SafeDataBindingList<T> : List<T>
    {
        private IList<T> _innerList;

        private SafeDataBindingList(IList<T> list)
            : base(list.Count)
        {
            _innerList = list;

            ProxyGenerator generator = new ProxyGenerator();

            foreach (T obj in list)
            {
                this.Add((T)generator.CreateClassProxy(typeof(T), new DataObjectInterceptor(obj)));
            }
        }

        public IList<T> InnerList
        {
            get { return _innerList; }
        }

        /// <summary>
        /// Creates a safe-wrapper around a list if needed for
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static IList<T> Create(IList<T> list)
        {
            if (list.Count <= 1)
                return list;

            string t1 = "";
            string t2 = "";

            t1 = list[0].GetType().ToString();

            bool uniformList = true;
            for (int i = 1; i < list.Count; i++)
            {
                t2 = list[i].GetType().ToString();
                if (t1 == t2)
                    continue;
                else
                {
                    uniformList = false;
                    break;
                }
            }

            if (uniformList)
                return list;

            return new SafeDataBindingList<T>(list);
        }
    }

    public class SafeDataBindingSet<T> : HashedSet<T>
    {
        private ISet<T> _innerSet;

        private SafeDataBindingSet(ISet<T> set)
            : base()
        {
            _innerSet = set;

            ProxyGenerator generator = new ProxyGenerator();

            foreach (T obj in set)
            {
                this.Add((T)generator.CreateClassProxy(typeof(T), new DataObjectInterceptor(obj)));
            }
        }

        public ISet<T> InnerSet
        {
            get { return _innerSet; }
        }

        /// <summary>
        /// Creates a safe-wrapper around a list if needed for
        /// </summary>
        /// <param name="set"></param>
        /// <returns></returns>
        public static ISet<T> Create(ISet<T> set)
        {
            if (set.Count <= 1)
                return set;

            string t1 = "";
            string t2 = "";

            bool uniformSet = true;
            foreach (T obj in set)
            {
                if (t1 == "")
                {
                    t1 = obj.GetType().ToString();
                    continue;
                }

                t2 = obj.GetType().ToString();

                if (t1 == t2)
                    continue;
                else
                {
                    uniformSet = false;
                    break;
                }
            }

            if (uniformSet)
                return set;

            return new SafeDataBindingSet<T>(set);
        }
    }

    public class DataObjectInterceptor : IInterceptor
    {
        private static object _syncRoot = new object();
        private static Dictionary<string, MethodInfo> _methodCache = new Dictionary<string, MethodInfo>();
        private object _target = null;

        public DataObjectInterceptor(object target)
        {
            _target = target;
        }

        public object Intercept(IInvocation invocation, params object[] args)
        {
            // it's possible that the type that the proxy was built on is not the type of
            // the _target object.  If it is, simply invoke MethodInfo, if it's not, we have
            // to find the appropriate MethodInfo on the unknown type.
            if (invocation.Method.ReflectedType.ToString() == invocation.InvocationTarget.GetType().ToString())
            {
                return invocation.Method.Invoke(_target, args);
            }
            else
            {
                MethodInfo method = GetMethod(invocation);
                return method.Invoke(_target, args);
            }
        }

        private MethodInfo GetMethod(IInvocation invocation)
        {

            Type targetType = _target.GetType();

            string methodKey = GetMethodKey(targetType, invocation.Method.Name);

            if (_methodCache.ContainsKey(methodKey))
                return _methodCache[methodKey];
            else
            {
                MethodInfo methodInfo = null;
                if (invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_"))
                    methodInfo = GetPropertyMethod(targetType, invocation);
                else
                {
                    methodInfo = GetMethod(targetType, invocation.Method.Name);
                }

                lock (_syncRoot)
                {
                    if (methodInfo != null && !_methodCache.ContainsKey(methodKey))
                        _methodCache.Add(methodKey, methodInfo);
                }

                return methodInfo;
            }
        }

        private MethodInfo GetMethod(Type targetType, string methodName)
        {
            // search class hierarchy for method
            Type type = targetType;
            do
            {
                // Use DeclaredOnly to see if we can get the method directly from this type
                MethodInfo method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

                if (method != null)
                    return method;

                type = type.BaseType;
            } while (type != null);

            return null;
        }

        private MethodInfo GetPropertyMethod(Type targetType, IInvocation invocation)
        {
            string propertyName = invocation.Method.Name.Split('_')[1];
            bool isGet = invocation.Method.Name.StartsWith("get_");

            Type type = targetType;
            PropertyInfo propertyInfo = null;

            do
            {
                propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

                if (propertyInfo != null)
                    break;

                type = type.BaseType;

            } while (type != null);

            if (propertyInfo == null)
                return null;

            if (isGet)
                return propertyInfo.GetGetMethod();
            else
                return propertyInfo.GetSetMethod();
        }

        private string GetMethodKey(Type targetType, string methodName)
        {
            return targetType.ToString() + "." + methodName;
        }
    }
}

_________________
Mike Abraham


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 26, 2007 12:06 pm 
Newbie

Joined: Tue Jun 26, 2007 11:39 am
Posts: 1
Clearing the session worked for me.

I got the reflection error in ASP.NET while trying to bind a list to a gridview. The gridview's databinder uses reflection to get the properties to auto-populate. However, before I got the list, I'd retrieve a single User record to populate a label.

As was described earlier, getting the single User seemed to turn the object from a proxy to concrete. Then, when I went to list all my users, they were all proxies except for that one record I'd retrieve earlier which remained concrete. Grids always want the datasource to be all the same type of object, and the reflection considers the proxy and the contrete objects to be of different types, even though they have the same propeties.

So I simply told my session to clear between requests. This isn't always the best way to do things because a Clear will also delete any pending writes. So if this is the only solution, and you have a lot of reads and writes, you may have to juggle your flushes, commits, and clears.


Top
 Profile  
 
 Post subject: The Binding Util Worked for Me
PostPosted: Fri Jun 06, 2008 11:26 am 
Newbie

Joined: Fri May 09, 2008 10:29 am
Posts: 4
I had this same issue, and I tried the SafeDataBindingList method. I had to modify slightly, as Castle has changed their interfaces a bit, but so far so good.

Code:
    public class DataObjectInterceptor : IInterceptor
    {
        private static object _syncRoot = new object();
        private static Dictionary<string, MethodInfo> _methodCache = new Dictionary<string, MethodInfo>();
        private object _target = null;

        public DataObjectInterceptor(object target)
        {
            _target = target;
        }

        public virtual void Intercept(IInvocation invocation)
        {
            Intercept(invocation, null);
        }

        public virtual void Intercept(IInvocation invocation, params object[] args)
        {
            // it's possible that the type that the proxy was built on is not the type of
            // the _target object.  If it is, simply invoke MethodInfo, if it's not, we have
            // to find the appropriate MethodInfo on the unknown type.
            if (invocation.Method.ReflectedType.ToString() == invocation.InvocationTarget.GetType().ToString())
            {
                invocation.ReturnValue = invocation.Method.Invoke(_target, args);
            }
            else
            {
                MethodInfo method = GetMethod(invocation);
                invocation.ReturnValue = method.Invoke(_target, args);
            }
        }

        private MethodInfo GetMethod(IInvocation invocation)
        {

            Type targetType = _target.GetType();

            string methodKey = GetMethodKey(targetType, invocation.Method.Name);

            if (_methodCache.ContainsKey(methodKey))
                return _methodCache[methodKey];
            else
            {
                MethodInfo methodInfo = null;
                if (invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_"))
                    methodInfo = GetPropertyMethod(targetType, invocation);
                else
                {
                    methodInfo = GetMethod(targetType, invocation.Method.Name);
                }

                lock (_syncRoot)
                {
                    if (methodInfo != null && !_methodCache.ContainsKey(methodKey))
                        _methodCache.Add(methodKey, methodInfo);
                }

                return methodInfo;
            }
        }

        private MethodInfo GetMethod(Type targetType, string methodName)
        {
            // search class hierarchy for method
            Type type = targetType;
            do
            {
                // Use DeclaredOnly to see if we can get the method directly from this type
                MethodInfo method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

                if (method != null)
                    return method;

                type = type.BaseType;
            } while (type != null);

            return null;
        }

        private MethodInfo GetPropertyMethod(Type targetType, IInvocation invocation)
        {
            string propertyName = invocation.Method.Name.Split('_')[1];
            bool isGet = invocation.Method.Name.StartsWith("get_");

            Type type = targetType;
            PropertyInfo propertyInfo = null;

            do
            {
                propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

                if (propertyInfo != null)
                    break;

                type = type.BaseType;

            } while (type != null);

            if (propertyInfo == null)
                return null;

            if (isGet)
                return propertyInfo.GetGetMethod();
            else
                return propertyInfo.GetSetMethod();
        }

        private string GetMethodKey(Type targetType, string methodName)
        {
            return targetType.ToString() + "." + methodName;
        }
    }


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.