Hi folks,

Could I get your feedback on this one? Am I missing something?

Thanks,

From: Segura, Eduardo [Tech]
Sent: Tuesday, August 17, 2010 1:29 PM
To: '[email protected]'
Subject: .Cacheable().Fetch() throws 'Exception occurred getter of xxx'

I'm wondering if this is the right way to use second-level caching along with 
eagerly loading a collection.
This code is equivalent to a query that we are issuing from a fairly large 
application. I've stripped it down to the very minimum while still throwing the 
exception.
(My apologies for the rather large email, but I want to provide as much 
information up-front as possible)

I have this test set up:

        [TestMethod]
        public void FindWithFetchAndCacheableTest()
        {
            IPersistenceService ps = 
PersistenceServiceFactory.CreateService(PersistenceServiceType.Hibernate);

            IList<ParentObject> pos = ps.Find<ParentObject, 
IQueryable<ParentObject>>(ParentObjects =>
                from po in ParentObjects
                select po)
                .Cacheable()
                .Fetch(po => po.ChildObjects).ToList();

            Assert.IsTrue(pos.Count > 0);
        }

My uneducated guess:
--------------------------------------
The lambda expression in Fetch() is being used as a 'resultTransfomer' here:
(NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.cs:line 335, using NH3.0.0Alpha1)

protected override object GetResultColumnOrRow(object[] row, IResultTransformer 
resultTransformer, IDataReader rs,
ISessionImplementor session)
{
                row = ToResultRow(row); <-- after this assignment, row is an 
Array[1] holding my object
                bool hasTransform = HasSelectNew || resultTransformer != null;  
<-- at this point, resultTransformer has a lambda

                ...

                else if (!hasTransform)
                {
                                return row.Length == 1 ? row[0] : row; <-- the 
object is not extracted from the array, because of the lambda
                }
}

And this method ends up returning an array (object[1] = [{ ParentObject}]), 
instead of returning the object itself.

Then later on, since the 'object[1]' array doesn't have an 'Id' property, this 
line throws the exception:
(NHibernate.Properties.BasicPropertyAccessor.cs:Line 207 (BasicGetter.Get)):
public object Get(object target)
{
                try
                {
                                return property.GetValue(target, new 
object[0]); <-- target is not {ParentObject}, but an object[1] instead
                }
                catch (Exception e)
                {
                                throw new PropertyAccessException(e, "Exception 
occurred", false, clazz, propertyName);
                }
}

My classes:
------------------------------------------------------

    public class ParentObject
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual ISet<ChildObject> ChildObjects { get; set; }

        public virtual void AddChildObject(ChildObject co)
        {
            this.ChildObjects.Add(co);
            co.Parent = this;
        }
    }

    public class ChildObject
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual ParentObject Parent { get; set; }
    }


Mappings:
----------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="PersistenceLayer.Test.Model.ParentObject, PersistenceLayer.Test">
    <cache usage="read-write"/>
    <id name="Id">
      <generator class="native"/>
    </id>
    <property name="Name"/>
    <set name="ChildObjects" inverse="true" cascade="all-delete-orphan">
      <cache usage="read-write"/>
      <key column="ParentId"/>
      <one-to-many class="PersistenceLayer.Test.Model.ChildObject"/>
    </set>
  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="PersistenceLayer.Test.Model.ChildObject, PersistenceLayer.Test">
    <cache usage="read-write"/>
    <id name="Id">
      <generator class="native"/>
    </id>
    <property name="Name"/>
    <many-to-one name="Parent" column="ParentId" not-null="true"/>
  </class>
</hibernate-mapping>



But it throws this exception:

Test method 
PersistenceLayer.Test.PersistenceServiceTest.FindWithFetchAndCacheableTest 
threw exception:  NHibernate.PropertyAccessException: Exception occurred getter 
of PersistenceLayer.Test.Model.ParentObject.Id --->  
System.Reflection.TargetException: Object does not match target type..
System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, 
Binder binder, Object[] parameters, CultureInfo culture, Boolean 
skipVisibilityChecks)
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, 
Binder binder, Object[] parameters, CultureInfo culture)
System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags 
invokeAttr, Binder binder, Object[] index, CultureInfo culture)
System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
NHibernate.Properties.BasicPropertyAccessor.BasicGetter.Get(Object target) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Properties\BasicPropertyAccessor.cs: 
line 207
NHibernate.Properties.BasicPropertyAccessor.BasicGetter.Get(Object target) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Properties\BasicPropertyAccessor.cs: 
line 211
NHibernate.Tuple.Entity.AbstractEntityTuplizer.GetIdentifier(Object entity) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Tuple\Entity\AbstractEntityTuplizer.cs: 
line 139
NHibernate.Persister.Entity.AbstractEntityPersister.GetIdentifier(Object obj, 
EntityMode entityMode) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:
 line 3838
NHibernate.Persister.Entity.AbstractEntityPersister.IsTransient(Object entity, 
ISessionImplementor session) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:
 line 3629
NHibernate.Engine.ForeignKeys.IsTransient(String entityName, Object entity, 
Nullable`1 assumed, ISessionImplementor session) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Engine\ForeignKeys.cs: line 193
NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved(String 
entityName, Object entity, ISessionImplementor session) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Engine\ForeignKeys.cs: line 249
NHibernate.Type.ManyToOneType.Disassemble(Object value, ISessionImplementor 
session, Object owner) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Type\ManyToOneType.cs: line 137
NHibernate.Cache.StandardQueryCache.Put(QueryKey key, ICacheAssembler[] 
returnTypes, IList result, Boolean isNaturalKeyLookup, ISessionImplementor 
session) in d:\CSharp\NH\nhibernate\src\NHibernate\Cache\StandardQueryCache.cs: 
line 82
NHibernate.Loader.Loader.PutResultInQueryCache(ISessionImplementor session, 
QueryParameters queryParameters, IType[] resultTypes, IQueryCache queryCache, 
QueryKey key, IList result) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Loader\Loader.cs: line 1627
NHibernate.Loader.Loader.ListUsingQueryCache(ISessionImplementor session, 
QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Loader\Loader.cs: line 1593
NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters 
queryParameters, ISet`1 querySpaces, IType[] resultTypes) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Loader\Loader.cs: line 1567
NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.List(ISessionImplementor session, 
QueryParameters queryParameters) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Hql\Ast\ANTLR\Loader\QueryLoader.cs: 
line 298
NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, 
QueryParameters queryParameters) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Hql\Ast\ANTLR\QueryTranslatorImpl.cs: 
line 110
NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters 
queryParameters, ISessionImplementor session, IList results) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Engine\Query\HQLQueryPlan.cs: line 105
NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, 
QueryParameters queryParameters, IList results) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs: line 679
NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, 
QueryParameters parameters) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs: line 655
NHibernate.Impl.ExpressionQueryImpl.List() in 
d:\CSharp\NH\nhibernate\src\NHibernate\Impl\ExpressionQueryImpl.cs: line 63
NHibernate.Linq.NhQueryProvider.Execute(Expression expression) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs: line 31
NHibernate.Linq.NhQueryProvider.Execute[TResult](Expression expression) in 
d:\CSharp\NH\nhibernate\src\NHibernate\Linq\NhQueryProvider.cs: line 55
GetEnumerator()
ctor(IEnumerable`1 collection)
System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
PersistenceLayer.Test.PersistenceServiceTest.FindWithFetchAndCacheableTest() in 
.....\PersistenceServiceTest.cs: line 345

Thanks,
Eduardo

-- 
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/nhusers?hl=en.

Reply via email to