2011-01-20 4 views
2

J'utilise postgresql avec hibernate et j'aimerais insérer des données en bloc d'une table de modèles à une autre. Comment faire cela dans une requête native est clair pour moi, mais en HQL je ne sais pas vraiment comment atteindre mon résultat attendu. J'ai utilisé la syntaxe de http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-direct pour créer ma requête.HQL Bulk insert

@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") 

Mon Shema:

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) 
); 

Simplyfied mon modèle:

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) 
    ) 

Je reçois l'erreur suivante:

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) 

jeu est une entité qui a un identifiant long généré par une séquence.

Comme vous pouvez le voir, le jeu n'est pas dans ma table modèle, donc je devrais forcer l'identifiant du jeu dans ma requête. Est-ce que quelqu'un sait comment cela doit être fait?

Merci à l'avance pour votre temps, meilleures salutations m

PS: comment j'appelle la requête:

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

Entités:

public class Tile implements Serializable{ 

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

PS: le casting n » Je ne travaille pas non plus.

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

Répondre

-1

Je pense que vous ne pouvez pas exprimer cette requête dans HQL. Mise en veille prolongée documentation décrit plusieurs limites de INSERT ... SELECT ... requêtes, en particulier

select_statement can be any valid HQL select query, with the caveat that the return types must match the types expected by the insert. Currently, this is checked during query compilation rather than allowing the check to relegate to the database.

Puisque vous ne pouvez pas exprimer dans la requête le fait que le :game a un type de Game, la compilation de cette requête ne réussit jamais. Essayez d'utiliser une requête SQL native à la place.

+0

Je comprends. Merci beaucoup. J'espérais revenir autour de ça de toute façon. Peut-être dans la prochaine version de jpa. :) – mkuff

+1

Ceci est incorrect. Je l'ai eu pour travailler. Peut-être que c'est parce que je suis sur Hibernate 3.6 et que vous aviez quelque chose de plus ancien. Voir ma réponse ci-dessous. –

2

Essayez avec:

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

et

query.setEntity("game", game);

Je suppose que vous avez également une classe nommée Tile et x, y, tileOverlay ... sont des propriétés de cette catégorie. A partir des documents de référence d'hibernation: "La pseudo-syntaxe pour les instructions INSERT est: INSERT INTO EntityName properties_list select_statement". En ce qui concerne la fonction cast, "cast (... as ...), où le second argument est le nom d'un type Hibernate", cela devrait fonctionner.

Je ne l'ai pas essayé avec des entités mais cela a bien fonctionné avec des types simples (octets, entiers ...).

+1

Cela valait le coup d'essayer, mais il se bloque avec une exception nullpointer. semble qu'il ne peut pas rechercher la classe de distribution en ce moment. salutations – mkuff

+1

À droite, il se bloque avec un NPE. Pour contourner ce problème, il a fallu remplacer 'cast (: game as Game)' par 'g' et ajouter ', Game g où g =: game' à la clause from. Cela produit une jointure inutile, mais continuons à utiliser HQL à la place pour aller à SQLquery. – jorgegm

0

J'ai trouvé comment faire cela à partir du commentaire de jorgegm ci-dessus, que je souhaite était sa réponse réelle depuis sa réponse originale donne un NPE.

Vous voulez créer votre requête comme ceci:

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 

Ensuite, appelez

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

Je l'ai fait en utilisant Hibernate 3.6 et il fonctionne comme un charme.