Hibernate:使用 select 和命名参数插入实体
Hibernate: insert in entity using select with named parameters
我有一个非常具体的问题,我必须做类似的事情(在 HQL 中):
insert into EntityA(field1, field2, field3, field4, field5)
select
:paramForField1,
:paramForField2,
:paramForField3,
:paramForField4,
:paramForField5
from
EntityB
where
...
正在使用 Query.setParameter(String, Object)
(JavaDoc) 传递参数,它们是字符串、字符串、字符串、日期和枚举。
虽然参数数量是正确的(五个字段的五个参数),但 Hibernate 不断引发以下异常:
...
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)
...
我正在使用 Hibernate 3.3.2 GA。
提前致谢。
我猜想Hibernate并没有为此做好准备。为什么需要将table EntityB的列名设置为参数?您是否考虑过只连接查询字符串?
试试这个:
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 不支持参数化的 INSERT 或 SELECT。您只能在 WHERE 子句中使用参数。
任何 SQL 字符串格式都容易受到 SQL injection 的影响,这就是为什么您需要使用我建议的 Java 反射习惯用法。如果您没有提供有效的 EntityA 字段名称,则该字段将不会被解析并会抛出异常。
这样您就可以构建动态查询并确保您的代码不会暴露给 SQL 注入。
从 hibernate 4.3 开始,这是可能的。 hibernate 4.3 之前的版本不支持 select 子句中的参数。
我有一个非常具体的问题,我必须做类似的事情(在 HQL 中):
insert into EntityA(field1, field2, field3, field4, field5)
select
:paramForField1,
:paramForField2,
:paramForField3,
:paramForField4,
:paramForField5
from
EntityB
where
...
正在使用 Query.setParameter(String, Object)
(JavaDoc) 传递参数,它们是字符串、字符串、字符串、日期和枚举。
虽然参数数量是正确的(五个字段的五个参数),但 Hibernate 不断引发以下异常:
...
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)
...
我正在使用 Hibernate 3.3.2 GA。
提前致谢。
我猜想Hibernate并没有为此做好准备。为什么需要将table EntityB的列名设置为参数?您是否考虑过只连接查询字符串?
试试这个:
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 不支持参数化的 INSERT 或 SELECT。您只能在 WHERE 子句中使用参数。
任何 SQL 字符串格式都容易受到 SQL injection 的影响,这就是为什么您需要使用我建议的 Java 反射习惯用法。如果您没有提供有效的 EntityA 字段名称,则该字段将不会被解析并会抛出异常。
这样您就可以构建动态查询并确保您的代码不会暴露给 SQL 注入。
从 hibernate 4.3 开始,这是可能的。 hibernate 4.3 之前的版本不支持 select 子句中的参数。