What I am trying is to map class hierarchy "A : PO, AA : A, B : PO, B.Ref has type A" to database. I expect queries on A or PO (which are abstract classes) to return objects of their type. If I remove 'lazy="false"' from HBM file, it generates different query which works. But when I do query just for Bs and try to use reference Ref to A, I get proxy over A and not over correct type (in this example AA). The workaround is to disable lazy loading, but that generates wrong query.
Few words about chosen inheritance type -- the overall hierarchy I am using is very large and I need to do query on abstract classes. The only one way to do this is to use discriminators, so that NH doesn't have to generate query over all tables in the class hierarchy. Also, I need to use multiple tables, which gives only one possibility for inheritance strategy - subclass + join.
So, I have this issues:
- generated query is wrong if lazy="false"
- proxy is generated over queried type instead of actual type
I know that the purpose of lazy loading is to prevent actual loading from database, but I think there should be an option to check underlying type (in this case, it would be just a query on _discriminator of table PO, which could be performed in a left join manner).
Hibernate version:
SVN head
Mapping documents:
Code:
<hibernate-mapping auto-import="false" xmlns="urn:nhibernate-mapping-2.2">
<class name="Test.PO" table="t__PO" discriminator-value="t__PO" lazy="false">
<id column="_id" type="Int64">
<generator class="native" />
</id>
<discriminator column="_discriminator" type="String" />
<subclass name="Test.B" discriminator-value="t__B">
<join table="t__B" fetch="select">
<key column="_id" />
<property name="Hoo" column="Hoo" type="Int32" />
<many-to-one name="Ref" column="Ref" class="Test.A" />
</join>
</subclass>
<subclass name="Test.A" discriminator-value="t__A" lazy="false">
<join table="t__A" fetch="select">
<key column="_id" />
<property name="Foo" column="Foo" type="Int32" />
</join>
<subclass name="Test.AA" discriminator-value="t__AA">
<join table="t__AA" fetch="select">
<key column="_id" />
<property name="Goo" column="Goo" type="Int32" />
</join>
</subclass>
</subclass>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
session.CreateCriteria<Test.PO> ().List<Test.PO> ();
Full stack trace of any exception that occurs:Code:
Unhandled Exception: System.InvalidOperationException: Unable to execute query. ---> NHibernate.ADOException: could not execute query
[ SELECT this_._id as column1_0_1_, this_._discriminator as column2_0_1_, a2_._id as column1_0_0_, a2_1_.Foo as Foo2_0_, a2_._discriminator as column2_0_0_ FROM t__PO this_ left outer join t__PO a2_ on this_1_.Ref=a2_._id left outer join t__A a2_1_ on a2_._id=a2_1_._id ]
[SQL: SELECT this_._id as column1_0_1_, this_._discriminator as column2_0_1_, a2_._id as column1_0_0_, a2_1_.Foo as Foo2_0_, a2_._discriminator as column2_0_0_ FROM t__PO this_ left outer join t__PO a2_ on this_1_.Ref=a2_._id left outer join t__A a2_1_ on a2_._id=a2_1_._id] ---> MySql.Data.MySqlClient.MySqlException: Unknown column 'this_1_.Ref' in 'on clause'
at MySql.Data.MySqlClient.PacketReader.CheckForError () [0x00000]
at MySql.Data.MySqlClient.PacketReader.ReadHeader () [0x00000]
at MySql.Data.MySqlClient.PacketReader.OpenPacket () [0x00000]
at MySql.Data.MySqlClient.NativeDriver.ReadResult (System.Int64& affectedRows, System.Int64& lastInsertId) [0x00000]
at MySql.Data.MySqlClient.CommandResult.ReadNextResult (Boolean isFirst) [0x00000]
at MySql.Data.MySqlClient.CommandResult..ctor (MySql.Data.MySqlClient.Driver d, Boolean isBinary) [0x00000]
at MySql.Data.MySqlClient.NativeDriver.SendQuery (System.Byte[] bytes, Int32 length, Boolean consume) [0x00000]
at MySql.Data.MySqlClient.MySqlCommand.GetNextResultSet (MySql.Data.MySqlClient.MySqlDataReader reader) [0x00000]
at (wrapper remoting-invoke-with-check) MySql.Data.MySqlClient.MySqlCommand:GetNextResultSet (MySql.Data.MySqlClient.MySqlDataReader)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult () [0x00000] --- End of inner exception stack trace ---
at NHibernate.Loader.Loader.DoList (ISessionImplementor session, NHibernate.Engine.QueryParameters queryParameters) [0x00000]
at NHibernate.Loader.Loader.ListIgnoreQueryCache (ISessionImplementor session, NHibernate.Engine.QueryParameters queryParameters) [0x00000]
at NHibernate.Loader.Loader.List (ISessionImplementor session, NHibernate.Engine.QueryParameters queryParameters, ISet`1 querySpaces, NHibernate.Type.IType[] resultTypes) [0x00000]
at NHibernate.Loader.Criteria.CriteriaLoader.List (ISessionImplementor session) [0x00000]
at NHibernate.Impl.SessionImpl.List (NHibernate.Impl.CriteriaImpl criteria, IList results) [0x00000] --- End of inner exception stack trace ---
Name and version of the database you are using:MySql 5.0.x
The generated SQL (show_sql=true):Code:
SELECT this_._id as column1_0_1_, this_._discriminator as column2_0_1_, a2_._id as column1_0_0_, a2_1_.Foo as Foo2_0_, a2_._discriminator as column2_0_0_ FROM t__PO this_ left outer join t__PO a2_ on this_1_.Ref=a2_._id left outer join t__A a2_1_ on a2_._id=a2_1_._id