简体   繁体   中英

Hibernate: insert in entity using select with named parameters

I have a very specific problem in which I must do something like (in HQL):

insert into EntityA(field1, field2, field3, field4, field5)
select
    :paramForField1, 
    :paramForField2,
    :paramForField3,
    :paramForField4,
    :paramForField5
from 
    EntityB
where 
    ...

The parameters are being passed using Query.setParameter(String, Object) ( JavaDoc ) and they are String, String, String, Date and an Enum.

Although the parameter number is right (five parameters for five fields), Hibernate keeps raising the following exception:

...
Caused by: org.hibernate.QueryException: number of select types did not match those for insert [insert into ...]
    at org.hibernate.hql.ast.tree.IntoClause.validateTypes(IntoClause.java:116)
    at org.hibernate.hql.ast.tree.InsertStatement.validate(InsertStatement.java:57)
    at org.hibernate.hql.ast.HqlSqlWalker.postProcessInsert(HqlSqlWalker.java:701)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.insertStatement(HqlSqlBaseWalker.java:513)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:255)
    at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:254)
    at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185)
    at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
    at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:94)
    at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)
    at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135)
    at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1651)
    ...

I'm using Hibernate 3.3.2 GA.

Thanks in advance.

Starting with hibernate 4.3 this is possible. Versions before hibernate 4.3 did not support parameters in the select clause.

Try this instead:

Class<?> entityAClass = EntityA.class;

Field field1 = entityAClass.getDeclaredField("paramForField1");
field1.setAccessible(true); 
String paramForField1 = field1.getName();

Field field2 = entityAClass.getDeclaredField("paramForField2");
field2.setAccessible(true); 
String paramForField2 = field2.getName();

Field field3 = entityAClass.getDeclaredField("paramForField3");
field3.setAccessible(true); 
String paramForField3 = field3.getName();

String hqlInsert = String.format(
    "insert into EntityA(%1$s, %2$s, %3$s)" + 
    "select c.%1$s, c.%2$s, c.%3$s from EntityB b" + 
    "where ...", 
    paramForField1, paramForField2, paramForField3);
int createdEntities = s.createQuery( hqlInsert )
    .executeUpdate();

Hibernate doesn't support parametrized INSERTs or SELECTs. You can use parameters in the WHERE clause only.

Any SQL string formatting is susceptible to SQL injection , that's why you need to use the Java Reflection idiom I suggested. If you don't supply a valid EntityA field name, then the field won't be resolved and an exception will be thrown.

This way you can build a dynamic query and also make sure you don't expose your code to SQL injection.

I would guess that Hibernate is not prepared for this. Why you need to set the column names of table EntityB as parameters? Did you think of just concatenating the query string?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM