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.  [ 2 posts ] 
Author Message
 Post subject: Query Set Contents
PostPosted: Thu Jul 03, 2008 8:21 pm 
Newbie

Joined: Mon Sep 26, 2005 12:34 pm
Posts: 7
I'm having some trouble querying out the contents of a set relation using either HQL or Criteria queries.

For the purposes of describing this problem, I have three tables that map to two classes: Tasks, TaskItems, and Items. The Tasks and Items tables map to classes directly. TaskItems is used to persist the Task class having an ISet<Item> collection property. The TaskItems table consists solely of the primary keys of the Task and Item tables that are connected.

For reasons having to do with the more complex reality of my setup, there is no direct relationship from the Items back to the Tasks at the class level.

I'm trying to write a query, either in HQL or as a Criteria query, that gives me the distinct Items that are referenced by Tasks with certain (simple) conditions. I can express the conditions trivially in either HQL or Criteria queries. However, getting the distinct contents of the Task.Items sets is proving difficult.

I got NHibernate to run the query I want it to with this HQL:

select distinct contents(t.Items) from Tasks t where t.Property = 2

NHibernate properly runs something like:

select distinct ti.item_id from tasks t inner join taskitems ti on t.task_id = ti.task_id

And then starts trying to load the actual item records, and that's where the problem occurs. Hibernate tries to run the "select * from items where item_id = :p0" query before it finishes reading the results from the the "select distinct ..." query, and PostgreSQL/Npgsql does not like this and throws an exception.

I did some more digging, and this appears to have something to do with a recent optimization in the beta versions of npgsql. Specifically, npgsql used to pre-buffer all the results into the data reader, where now it streams the results as needed. The release notes for the version in which this was introduced (http://pgfoundry.org/frs/shownotes.php?release_id=1124) indicate that the ADO.NET API does not technically allow working with a connection while an IDataReader is open, but that the prior behavior of npgsql happened to allow that as a side effect. It appears from looking at how NHibernate is operating that running this hql query would require support for that improper behavior on any database.

I can work around this by turning off the streaming behavior with a connection string setting, but that's undesirable, and from what I can understand of this issue, it seems like something that may need fixing generally.

From a quick look at the code, it seems like if I could somehow tell the query to return proxies with just the PK filled instead of fully populated objects, that would work. Criteria queries seem to be more prone to returning proxies, but I could not find a way to express that query as a criteria query.

Hibernate version: 1.2.0

Name and version of the database you are using: PostgreSQL 8.3.3 / npgsql 2.0.0 Beta 4

Stack trace of exception:

Code:
   at Npgsql.NpgsqlCommand.CheckConnectionState()
   at Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior cb)
   at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
   at NHibernate.Impl.BatcherImpl.ExecuteReader(IDbCommand cmd)
   at NHibernate.Loader.Loader.GetResultSet(IDbCommand st, RowSelection selection, ISessionImplementor session)
   at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   at NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, Type optionalEntityName, Object optionalIdentifier, IEntityPersister persister)
   --- End of inner exception stack trace ---
   at NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, Type optionalEntityName, Object optionalIdentifier, IEntityPersister persister)
   at NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId)
   at NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session)
   at NHibernate.Persister.Entity.AbstractEntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)
   at NHibernate.Impl.SessionImpl.DoLoad(Type theClass, Object id, Object optionalObject, LockMode lockMode, Boolean checkDeleted)
   at NHibernate.Impl.SessionImpl.DoLoadByClass(Type clazz, Object id, Boolean checkDeleted, Boolean allowProxyCreation)
   at NHibernate.Impl.SessionImpl.InternalLoad(Type clazz, Object id, Boolean eager, Boolean isNullable)
   at NHibernate.Type.EntityType.ResolveIdentifier(Object id, ISessionImplementor session)
   at NHibernate.Type.EntityType.ResolveIdentifier(Object id, ISessionImplementor session, Object owner)
   at NHibernate.Type.EntityType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner)
   at NHibernate.Hql.Classic.QueryTranslator.GetResultColumnOrRow(Object[] row, IResultTransformer resultTransformer, IDataReader rs, ISessionImplementor session)
   at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
   at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters)
   at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet querySpaces, IType[] resultTypes)
   at NHibernate.Hql.Classic.QueryTranslator.List(ISessionImplementor session, QueryParameters queryParameters)
   at NHibernate.Impl.SessionImpl.Find(String query, QueryParameters parameters, IList results)
   at NHibernate.Impl.QueryImpl.List(IList results)


Top
 Profile  
 
 Post subject: Found solution
PostPosted: Mon Jul 07, 2008 11:23 am 
Newbie

Joined: Mon Sep 26, 2005 12:34 pm
Posts: 7
After searching and digging, the problem is that NpgsqlDriver currently claims true for SupportsMultipleOpenReaders. Subclassing the driver to change that to false fixes it.


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