I'm trying to use Hibernate to access a database that includes a unique many-to-many relationship between two entities with a couple of extra fields. My first attempt is to use a set in one of the entity objects and component as the member-type of that set. I can query both entity tables without any trouble, but when I try to join them Hibernate generates invalid SQL which causes it to die with a JDBC exception.
Two questions:
1. As far as I can tell, this is a bug in Hibernate. If I give it an invalid mapping document, it should catch the error, not generate SQL referring to a "blank" field-name. Is there something I'm missing?
2. Is this the right way to map such a relationship? Each person can be associated with multiple addresses, and each address with multiple people, but there should only be one status for a given <address,person> pair. Right now I have a
public PersonsAddress[] getAddresses() member of
Person, and I was planning to write an
addAddress() method. There should be no
removeAddress method; instead that will be accomplished by setting
status to "invalid".
Hibernate version:
3.2.0.cr3
Mapping documents:
Code:
<class name="com.lmert.learnhib.Person" table="people"
discriminator-value="None" >
<id type="string" name="nick"
column="nick" access="field" unsaved-value="null" >
<generator class="com.lmert.learnhib.MeaninglessNickGenerator" />
</id>
<timestamp name="updateTime" column="update_time"
access="field" generated="always" />
<property name="name" type="java.lang.String" access="field" />
<set name="addresses" access="field" table="personXaddress" >
<key column="nick" />
<composite-element class="com.lmert.learnhib.PersonsAddress" >
<parent name="person" />
<many-to-one name="address" column="placeId" access="field"
class="com.lmert.learnhib.Address" />
<property name="updateTime" column="update_time" generated="always"
update="false" not-null="true" access="field" />
<property name="status" type="string" access="field" />
<property name="type" type="string" access="field" />
</composite-element>
</set>
</class>
<class name="com.lmert.learnhib.Address" table="addresses" >
<id
type="int"
column="placeId"
access="field" >
<generator class="native" />
</id>
<property name="street" type="java.lang.String" access="field" />
<property name="number" type="java.lang.String" access="field" />
<property name="unitNo" type="java.lang.String" access="field" />
<property name="cc" type="java.lang.String" access="field" />
<property name="city" type="java.lang.String" access="field" />
<property name="zip" type="java.lang.String" access="field" />
<property column="update_time" name="updateTime" type="timestamp"
access="field" />
<property name="placeTitle" type="java.lang.String" />
</class>
Code between sessionFactory.openSession() and session.close():I'm using the following HQL query:
Code:
select new list(p,p.addresses) from Person p WHERE p.nick='davidl'
Full stack trace of any exception that occurs:Code:
2007-12-29 14:15:00,345 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1064, SQLState: 42000
2007-12-29 14:15:00,370 [main] ERROR org.hibernate.util.JDBCExceptionReporter - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as col_1_0_ from people person0_ inner join personXaddress addresses1_ on person' at line 1
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.loader.Loader.doList(Loader.java:2147)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2028)
at org.hibernate.loader.Loader.list(Loader.java:2023)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:393)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
at com.lmert.learnhib.Main.main(Main.java:45)
Caused by: java.sql.SQLException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as col_1_0_ from people person0_ inner join personXaddress addresses1_ on person' at line 1
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2928)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1571)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1666)
at com.mysql.jdbc.Connection.execSQL(Connection.java:2994)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:936)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1030)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:186)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1668)
at org.hibernate.loader.Loader.doQuery(Loader.java:662)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
at org.hibernate.loader.Loader.doList(Loader.java:2144)
... 8 more
Name and version of the database you are using:5.0.32-Debian_7etch1-log ; JDBC driver mysql-connector-java-3.1.12-bin.jar
The generated SQL (show_sql=true):Code:
071229 14:15:00 711 Query select person0_.nick as col_0_0_, . as col_1_0_ from people person0_ inner join personXaddress addresses1_ on person0_.nick=addresses1_.nick where person0_.nick='davidl'
(from the MySQL server log...)