-->
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.  [ 6 posts ] 
Author Message
 Post subject: HQL entity aliases matching class name confuse NHibernate
PostPosted: Mon Jan 09, 2006 2:54 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Hibernate version: 1.0.1

I have two entities, which I'll call Foo and Bar, which are related in a many-to-many fashion. The "join" table is exposed as an entity in itself, which I'll call FooBar.

Mapping documents:

Code:
<hibernate-mapping
   xmlns="urn:nhibernate-mapping-2.0"
   default-cascade="none"
   default-access="field.camelcase-underscore"
   assembly="Entities"
   namespace="MyCompany.Entities">
   <class name="Foo" table="foo" lazy="true"   dynamic-update="true" select-before-update="true">
      <id name="Id" column="foo_id" type="String" length="10" unsaved-value="null" access="field.camelcase-underscore">
         <generator class="MyCompany.Entities.DataAccess.NHibernate.MyIdentifierGenerator, EntityAccess"/>
      </id>
      <property name="Name" column="name" type="String" length="50"  access="field.camelcase-underscore"/>
      <bag name="Bars" inverse="true" lazy="true" cascade="delete" access="field.camelcase-underscore">
         <key column="foo_id" />
         <one-to-many class="FooBar"/>
      </bag>
   </class>
</hibernate-mapping>

<hibernate-mapping
   xmlns="urn:nhibernate-mapping-2.0"
   default-cascade="none"
   default-access="field.camelcase-underscore"
   assembly="Entities"
   namespace="MyCompany.Entities">
   <class name="FooBar" table="foo_bar" lazy="true"   dynamic-update="true" select-before-update="true">
      <id name="Id" column="foo_bar_id" type="String" length="10" unsaved-value="null" access="field.camelcase-underscore">
         <generator class="MyCompany.Entities.DataAccess.NHibernate.MyIdentifierGenerator, EntityAccess"/>
      </id>
      <property name="IsPrimary" column="is_primary" type="Boolean"  access="field.camelcase-underscore"/>
      <many-to-one name="Foo" class="Foo" cascade="none"   column="foo_id"  access="field.camelcase-underscore"/>
      <many-to-one name="Bar" class="Bar" cascade="delete" column="bar_id"  access="field.camelcase-underscore"/>
   </class>
</hibernate-mapping>


<hibernate-mapping
   xmlns="urn:nhibernate-mapping-2.0"
   default-cascade="none"
   default-access="field.camelcase-underscore"
   assembly="Entities"
   namespace="MyCompany.Entities"
>
   <class name="Bar" table="bar" lazy="true"   dynamic-update="true" select-before-update="true">

      <id name="Id" column="bar_id" type="String" length="10" unsaved-value="null" access="field.camelcase-underscore">
         <generator class="MyCompany.Entities.DataAccess.NHibernate.MyIdentifierGenerator, EntityAccess"/>
      </id>
      <property name="Name" column="name" type="String" length="50"  access="field.camelcase-underscore"/>
      <bag name="Foos" inverse="true" lazy="true" cascade="delete" access="field.camelcase-underscore">
         <key column="bar_id" />
         <one-to-many class="FooBar"/>
      </bag>
   </class>
</hibernate-mapping>


If I execute this query:

Code:
SELECT Foo, FooBar, PrimaryBar
FROM Foo AS Foo
LEFT JOIN Foo.Bars AS FooBar
JOIN FooBar.Bar AS PrimaryBar
WHERE FooBar.IsPrimary = true


I get this exception:

Code:
QueryException: undefined alias or unknown mapping: MyCompany [SELECT Foo, MyCompany.Entities.FooBar, PrimaryBar
FROM MyCompany.Entities.Foo AS Foo
LEFT JOIN Foo.Bars AS FooBar
JOIN FooBar.Bar AS PrimaryBar
WHERE FooBar.IsPrimary = true]
   at NHibernate.Hql.PathExpressionParser.Token(String token, QueryTranslator q)
   at NHibernate.Hql.ParserHelper.Parse(IParser p, String text, String seperators, QueryTranslator q)
   at NHibernate.Hql.SelectParser.Token(String token, QueryTranslator q)
   at NHibernate.Hql.ClauseParser.Token(String token, QueryTranslator q)
   at NHibernate.Hql.ClauseParser.End(QueryTranslator q)
   at NHibernate.Hql.PreprocessingParser.End(QueryTranslator q)
   at NHibernate.Hql.ParserHelper.Parse(IParser p, String text, String seperators, QueryTranslator q)
   at NHibernate.Hql.QueryTranslator.Compile()
   at NHibernate.Hql.QueryTranslator.Compile(ISessionFactoryImplementor factory, IDictionary replacements, Boolean scalar)
   at NHibernate.Impl.SessionFactoryImpl.GetQuery(String queryString, Boolean shallow)
   at NHibernate.Impl.SessionImpl.GetQueries(String query, Boolean scalar)
   at NHibernate.Impl.SessionImpl.Find(String query, QueryParameters parameters)
   at NHibernate.Impl.QueryImpl.List()


If I don't specify the select list, or alias the entities differently than their class names, it works fine. This might not sound like a big deal, but we need specify the select list explicitly and want to use entity aliases that match the class names where possible, for other reasons ...


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 10, 2006 12:36 pm 
Expert
Expert

Joined: Fri May 13, 2005 11:13 am
Posts: 292
Location: Rochester, NY
In this particular case, the "FooBar" in the select list is redundant, since we already know IsPrimary = true because of the where clause.

What happens if you just leave "FooBar" out of the select list? It looks like that is the specific alias that is confusing NHibernate (it is the only one expanded in the exception message). If Foo works (I see no reason why PrimaryBar would be a problem) that would seem to focus the extent of the issue. Then I would open it up to Jira.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 10, 2006 1:08 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
The mapping shown is simplified; in the real case, FooBar has additional properties of interest, so it needs to be returned by the query.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 10, 2006 1:21 pm 
Expert
Expert

Joined: Fri May 13, 2005 11:13 am
Posts: 292
Location: Rochester, NY
Nonetheless, what happens when only FooBar is removed from the select list or given a different name?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 10, 2006 2:35 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
The HQL parser used in H2.1 and NH is pretty dumb and easily gets confused.

If you disable auto-import in your mappings (<hibernate-mapping auto-import="false">) you should be able to achieve what you want, but then you will have to use fully-qualified class names everywhere in your queries, unqualified class names won't work.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 11, 2006 12:29 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Thanks for the response, Sergey.

Disabling auto-import is definitely not an option for us -- besides making queries much easier to write, we depend on it. Our product is intended to be customized. The approach we have for this with our new domain layer & NHibernate is to require that subclasses/replacements of standard entities have the same class name, but different namespace. Then the customer simply registers their own DLL with customized entities & mapping, and standard queries still work, but create their extended entities. (For this to work of course, customized entities can only add new properties, not change or remove existing ones, even if the custom entity doesn't subclass the standard one or implement an interface common with the standard one.)

<sigh> We'll just have to live with naming aliases different than the class names. We may either go back to putting an ugly prefix on all our class names (some of our developers still hate namespaces and liked ugly class prefixes to distinguish in-house stuff), or use a "my" prefix on the aliases ...


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