【问题标题】:HQL Bulk insertHQL 批量插入
【发布时间】:2011-01-20 18:43:09
【问题描述】:

我正在使用带有 hibernate 的 postgresql,我想将模板表中的数据批量插入到另一个模板表中。如何在本机查询中做到这一点对我来说很清楚,但在 HQL 中我真的不知道如何达到我的预期结果。 我使用来自http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-direct 的语法来创建我的查询。

@NamedQuery(name="Tile.bulkLoadLevel", query="INSERT INTO Tile (x, y, game, tileOverlay, startTile, blockWalkable, sightBlocking)" +
        " SELECT t.x, t.y, :game as game, t.tileOverlay, t.startTile, t.blockWalkable, t.sightBlocking from TemplateQuestTile t")

我的谢玛:

CREATE TABLE tile
(
   x integer NOT NULL,
   y integer NOT NULL,
   blockwalkable boolean NOT NULL,
   sightblocking boolean NOT NULL,
   starttile boolean NOT NULL,
   imagepath character varying(255) NOT NULL,
   gameid bigint NOT NULL,
   CONSTRAINT tile_pkey PRIMARY KEY (gameid, x, y)
 );

简化了我的模板:

   CREATE TABLE templatequesttile
   (
     x integer NOT NULL,
     y integer NOT NULL,
     blockwalkable boolean NOT NULL,
     sightblocking boolean NOT NULL,
     starttile boolean NOT NULL,
     imagepath character varying(255) NOT NULL,
     questname character varying(255) NOT NULL,
     CONSTRAINT templatequesttile_pkey PRIMARY KEY (questname, questseries, x, y)
   )

我收到以下错误:

ERROR (SessionFactoryImpl.java:435) - Error in named query: Tile.bulkLoad
org.hibernate.QueryException: number of select types did not match those for insert [INSERT INTO Tile (x, y,    game, tileOverlay, startTile, blockWalkable, sightBlocking) SELECT t.x, t.y, :game, t.tileOverlay, t.startTile, t.blockWalkable, t.sightBlocking from net.hq.model.TemplateQuestTile t]
at org.hibernate.hql.ast.tree.IntoClause.validateTypes(IntoClause.java:115)
at org.hibernate.hql.ast.tree.InsertStatement.validate(InsertStatement.java:57)
at org.hibernate.hql.ast.HqlSqlWalker.postProcessInsert(HqlSqlWalker.java:715)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.insertStatement(HqlSqlBaseWalker.java:519)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:261)

游戏是具有由序列生成的长标识符的实体。

如您所见,游戏不在我的模板表中,因此我需要将游戏 ID 强制输入到我的查询中。有谁知道这是怎么做的吗?

提前感谢您的宝贵时间, 此致 米

PS:我如何调用查询:

Query query = em.createNamedQuery("Tile.bulkLoadLevel");
query.setParameter("game", game.getGameid());
int copyiedEntities = query.executeUpdate();

实体:

public class Tile implements Serializable{

@Id
private int x;
@Id
private int y;
@Id
@ManyToOne
@JoinColumn(name="gameid")
private Game game;

PS:演员表也不起作用。

java.lang.ExceptionInInitializerError 在 net.hq.process.db.PersistenceTest.setUp(PersistenceTest.java:58) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native 方法)在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) 在 org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:236) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 造成的: java.lang.NullPointerException 在 java.lang.Class.forName0(本机 方法)在 java.lang.Class.forName(Class.java:169) 在 org.hibernate.util.ReflectHelper.classForName(ReflectHelper.java:192) 在 org.hibernate.type.TypeFactory.heuristicType(TypeFactory.java:279) 在 org.hibernate.type.TypeFactory.heuristicType(TypeFactory.java:264) 在 org.hibernate.hql.ast.util.SessionFactoryHelper.findFunctionReturnType(SessionFactoryHelper.java:400) 在 org.hibernate.hql.ast.util.SessionFactoryHelper.findFunctionReturnType(SessionFactoryHelper.java:392) 在 org.hibernate.hql.ast.tree.MethodNode.dialectFunction(MethodNode.java:103) 在 org.hibernate.hql.ast.tree.MethodNode.resolve(MethodNode.java:78) 在 org.hibernate.hql.ast.HqlSqlWalker.processFunction(HqlSqlWalker.java:979) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.functionCall(HqlSqlBaseWalker.java:2529) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.selectExpr(HqlSqlBaseWalker.java:2129) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.selectExprList(HqlSqlBaseWalker.java:1983) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.selectClause(HqlSqlBaseWalker.java:1515) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:586) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.insertStatement(HqlSqlBaseWalker.java:510) 在 org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:261) 在 org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:254) 在 org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185) 在 org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136) 在 org.hibernate.engine.query.HQLQueryPlan.(HQLQueryPlan.java:101) 在 org.hibernate.engine.query.HQLQueryPlan.(HQLQueryPlan.java:80) 在 org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:98) 在 org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:562) 在 org.hibernate.impl.SessionFactoryImpl.(SessionFactoryImpl.java:424) 在 org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385) 在 org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954) 在 org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:891) 在 org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:57) 在 javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48) 在 javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32) 在 net.hq.util.Db.(Db.java:7) ... 17 更多

【问题讨论】:

    标签: hibernate insert hql jpa-2.0 bulk


    【解决方案1】:

    尝试:

    INSERT INTO Tile (x, y, game, tileOverlay, startTile, blockWalkable, SightBlocking) 选择 t.x, t.y, cast(:game as Game), t.tileOverlay, t.startTile, t.blockWalkable, t.sightBlocking from TemplateQuestTile t")

    query.setEntity("游戏", 游戏);

    我假设您还有一个名为 Tile 的类,而 x、y、tileOverlay... 是该类的属性。从休眠参考文档: "INSERT 语句的伪语法是:INSERT INTO EntityName properties_list 选择语句”。

    关于转换函数,“cast(... as ...),其中第二个参数是 Hibernate 类型的名称”,所以它应该可以工作。

    我没有尝试使用实体,但它适用于简单类型(字节、整数...)。

    【讨论】:

    • 值得一试,但它会因空指针异常而崩溃。看来他此时无法查找演员表。问候
    • 对,它与 NPE 一起崩溃。作为一种解决方法,它可以将 'cast(:game as Game)' 替换为 'g' 并将 ', Game g where g = :game' 添加到 from 子句。它会产生不必要的连接,但让我们继续使用 HQL 来代替 SQLquery。
    【解决方案2】:

    我从上面 jorgegm 的评论中弄清楚了如何做到这一点,我希望这是他的实际答案,因为他的原始答案给出了 NPE。

    您想像这样创建查询:

    INSERT INTO Tile (x, y, game, tileOverlay, startTile, blockWalkable, sightBlocking)
    SELECT t.x, t.y, g, t.tileOverlay, t.startTile, t.blockWalkable, t.sightBlocking 
      FROM TemplateQuestTile t,
           Game g
     WHERE g.id = :gameId
    

    然后,调用

    query.setParameter("gameId", game.getId());
    

    我使用 Hibernate 3.6 完成了这项工作,效果非常棒。

    【讨论】:

      【解决方案3】:

      我认为您无法在 HQL 中表达此查询。 Hibernate 文档描述了INSERT ... SELECT ... 查询的几个限制,尤其是

      select_statement 可以是任何有效的 HQL 选择查询,但需要注意的是返回类型必须与插入所期望的类型相匹配。目前,这是在查询编译期间检查的,而不是允许检查委托给数据库。

      由于您无法在查询中表达:game 的类型为Game,因此此查询的编译永远不会成功。

      尝试使用原生 SQL 查询。

      【讨论】:

      • 我明白了。非常感谢。无论如何,我希望能解决这个问题。也许在下一个 jpa 版本中。 :)
      • 这是不正确的。我让它工作。也许是因为我使用的是 Hibernate 3.6,而您使用的是旧版本。请参阅下面的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-15
      • 1970-01-01
      • 2012-02-16
      • 2023-04-09
      • 2020-10-24
      相关资源
      最近更新 更多