-->
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.  [ 1 post ] 
Author Message
 Post subject: invalid sql generated when compound key contains 'id' field?
PostPosted: Sat Jun 07, 2008 10:38 am 
Newbie

Joined: Fri Jun 06, 2008 6:14 pm
Posts: 2
Hi,
I've run into a situation where hibernate seems to generate invalid SQL if I have a property in a compound primary key named 'id'. Hopefully, someone can spot what I'm doing wrong here or confirm this is a bug.

Description
Below I have 2 pojos, A and B. A has a one to many relationship with B. Furthermore, B has a compound key consisting of 2 fields named id and type. The IdClass for B is B.BId. B also has a reference to its A.

The generated tables are as follows: (* denotes primary key)
A(id*, description)
B(id*, type*, a_id)

Source code
I'll omit imports, getters, and setters to try to shorten this post a little...
Code:
@NamedQuery(name = "A.findByB", query = "select a from B b join b.a a where b = ?0")
@Entity
public class A {
    @Id
    @GeneratedValue
    private long id;

    @OneToMany(targetEntity = B.class, mappedBy = "a", cascade = CascadeType.ALL)
    List<B> bs;

    private String description;
}


Code:
@Entity
@IdClass(B.BId.class)
public class B {
    @Id
    private String type;
    @Id
    private String id;
   
    @ManyToOne (
       targetEntity=A.class,
       fetch=FetchType.LAZY,
       cascade=CascadeType.ALL)
    private A a;

    public static class BId implements Serializable {

   public String id;
   public String type;
    }
}

Code:
public class ADao {

    @PersistenceContext
    private EntityManager entityManager;

    A save(A o) {
   return entityManager.merge(o);
    }

    public List<A> findByB(B b) {
   Query namedQuery = entityManager.createNamedQuery("A.findByB");
   namedQuery.setParameter(0, b);
   return (List<A>) namedQuery.getResultList();
    }
}

Code:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:applicationContext-server.xml" })
@Transactional
public class ADaoJpaTest extends AbstractJpaTests {
    @Autowired
    private ADao aDao;
    private A a;
    private B b;
   
   
    @Before public void setup() {
   
   a = new A();
   a.setDescription("test");
   List<B> bs = new ArrayList<B>();
   b = new B();
   b.setBId("123");
   b.setType("test");
   bs.add(b);
   a.setBs(bs);
   A newA = aDao.save(a);
    }
   
    @Transactional
    @Test public void findByB() {
   
   B b = a.getBs().get(0);

   List<A> as = aDao.findByB(b);
   Assert.assertTrue(as.size() > 0);
    }
}

Here is the relevant excerpt from my applicationContext
Code:
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="dataSource" ref="dataSource" />
   <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
         <property name="showSql" value="true" />
         <property name="generateDdl" value="true" />
         <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
      </bean>
   </property>
      
   <property name="jpaDialect" ref="jpaDialect" />
</bean>


Result
When I execute the previous test, the generated SQL for findByB() is
Quote:
Hibernate: insert into A (description) values (?)
Hibernate: select b0_.id as id1_1_, b0_.type as type1_1_, b0_.a_id as a3_1_1_, a1_.id

as id0_0_, a1_.description as descript2_0_0_ from B b0_ left outer join A a1_ on

b0_.a_id=a1_.id where b0_.id=? and b0_.type=?
Hibernate: insert into B (a_id, id, type) values (?, ?, ?)
Hibernate: select a1_.id as id0_, a1_.description as descript2_0_ from B b0_ inner join

A a1_ on b0_.a_id=a1_.id where b0_.id=(?, ?)
Jun 7, 2008 9:51:14 AM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1241, SQLState: 21000
Jun 7, 2008 9:51:14 AM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: Operand should contain 1 column(s)

I've made the invalid portion bold.

Now for the kicker, if I change B.id and B.BId.id to be named B.bid and B.BId.bid, respectively, then Hibernate generates the following SQL which executes without issue:
Quote:
Hibernate: insert into A (description) values (?)
Hibernate: select b0_.bid as bid1_1_, b0_.type as type1_1_, b0_.a_id as a3_1_1_, a1_.id

as id0_0_, a1_.description as descript2_0_0_ from B b0_ left outer join A a1_ on

b0_.a_id=a1_.id where b0_.bid=? and b0_.type=?
Hibernate: insert into B (a_id, bid, type) values (?, ?, ?)
Hibernate: select a1_.id as id0_, a1_.description as descript2_0_ from B b0_ inner join

A a1_ on b0_.a_id=a1_.id where (b0_.bid, b0_.type)=(?, ?)


So, is this a bug or am I overlooking something?

Hibernate version:I've tried with 3.2.6 and 3.3.0 cr1
I'm using MySQL 5.1.24. I have tried this with HSQL and it throws this exception for the original code and works if I change the id to bid as described above.
Code:
Caused by: org.hibernate.HibernateException: SqlNode's text did not reference expected number of columns
   at org.hibernate.hql.ast.tree.BinaryLogicOperatorNode.extractMutationTexts(BinaryLogicOperatorNode.java:156)
   at org.hibernate.hql.ast.tree.BinaryLogicOperatorNode.mutateRowValueConstructorSyntax(BinaryLogicOperatorNode.java:94)
   at org.hibernate.hql.ast.tree.BinaryLogicOperatorNode.mutateRowValueConstructorSyntaxesIfNecessary(BinaryLogicOperatorNode.java:71)
   at org.hibernate.hql.ast.tree.BinaryLogicOperatorNode.initialize(BinaryLogicOperatorNode.java:51)
   at org.hibernate.hql.ast.HqlSqlWalker.prepareLogicOperator(HqlSqlWalker.java:1006)
   at org.hibernate.hql.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:3992)
   at org.hibernate.hql.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1762)
   at org.hibernate.hql.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:776)
   at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:577)
   at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:281)
   at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:229)
   at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:228)
   at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:160)
   at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:111)
   at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
   at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)
   at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)
   at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:413)
   at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:361)
   at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1304)
   at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:854)
   at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:669)
   ... 71 more


Thanks for your help!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

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.