5 votes

JPA avec Hibernate 3.6.8.Final, PostgreSQL 9.1, SQLGrammarException - problème de configuration ? Instruction SQL bizarre

Editar : SOLVED C'est vrai. J'ai trouvé la chose qui m'a troublé. J'utilise pgadmin pour créer des tables et d'autres internes de base de données, vérifié en ce moment : si au moins une lettre dans le nom (nom de la table, nom de la colonne, nom du pk, etc) est en majuscule, alors pgadmin l'utilise dans la création SQL script tel quel, en utilisant des guillemets doubles, afin que PostgreSQL interprète le nom comme il a été écrit. Si on exécute le script suivant :

CREATE TABLE SAMPLE
(
  ID integer NOT NULL,
  TITLE character varying(100) NOT NULL,
  CONSTRAINT SAMPLE_ID_PK PRIMARY KEY (ID)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE SAMPLE
  OWNER TO postgres;_

il crée tout en minuscules, et la version originale de Sample.java fonctionne bien.


Qu'est-ce qui ne va pas ici ? Ce problème est-il spécifique à PostgreSQL 9.1 ou à PostgreSQL en général, ou bien une configuration d'Hibernate est-elle manquante ?

persistence.xml :

<persistence-unit name="com.sample.persistence.jpa" transaction-type="RESOURCE_LOCAL">
    <class>com.sample.persistence.Sample</class>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.connection.url" value="jdbc:postgresql:sample"/>
        <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
        <property name="hibernate.connection.username" value="postgres"/>
        <property name="hibernate.connection.password" value="postgres"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hbm2ddl.auto" value="update"/>
    </properties>
</persistence-unit>

Sample.java :

@Entity
@Table(name = "SAMPLE")
public class Sample {

    @Id
    @Column(name = "ID")
    private long id;

    @Column(name = "TITLE")
    private String title;

    public String getTitle() {
        return title;
    }
}

PersistenceMain.java :

public class PersistenceMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.sample.persistence.jpa");
        EntityManager em = emf.createEntityManager();

        Sample sample = em.find(Sample.class, 1l);

        System.out.println("Sample Title: " + sample.getTitle());

        em.close();

        emf.close();
    }
}

Exception :

...
Hibernate: 
    select
        sample0_.ID as ID0_0_,
        sample0_.TITLE as TITLE0_0_ 
    from
        SAMPLE sample0_ 
    where
        sample0_.ID=?
Exception in thread "main" javax.persistence.PersistenceException:     org.hibernate.exception.SQLGrammarException: could not load an entity:   [com.sample.persistence.Sample#1]
 ...
Caused by: org.postgresql.util.PSQLException: ERROR: relation "sample" does not exist
 ...

Évidemment, cette déclaration SQL ci-dessus :

select
    sample0_.ID as ID0_0_,
    sample0_.TITLE as TITLE0_0_ 
from
    SAMPLE sample0_ 
where
    sample0_.ID=?

n'est pas exécuté avec succès depuis le PostgreSQL lui-même (depuis pgadmin).

Mais, si je change Sample.java en :

@Entity
@Table(name = "\"SAMPLE\"")
public class Sample {

    @Id
    @Column(name = "\"ID\"")
    private long id;

    @Column(name = "\"TITLE\"")
    private String title;

    public String getTitle() {
        return title;
    }
}

ce qui est bizarre, ça marche.

Hibernate: 
    select
        sample0_."ID" as ID1_0_0_,
        sample0_."TITLE" as TITLE2_0_0_ 
    from
        "SAMPLE" sample0_ 
    where
        sample0_."ID"=?
Sample Title: Sample

Est-ce que hibernate.dialect est inutile ici, ou bien il ne fonctionne pas correctement avec PostgreSQL 9.1 ? De plus, j'aimerais ne pas taper les noms des colonnes s'ils sont identiques à ceux du champ, mais en majuscules, est-ce également possible ?

Merci.

4voto

Piotr Nowicki Points 7565

El @Table("\"...\"") consiste à forcer le fournisseur JPA à utiliser la valeur exacte que vous fournissez (c'est-à-dire à utiliser la casse exacte du nom de la table).

D'ailleurs, c'est similaire dans le monde PostgreSQL. Si vous invoquez CREATE TABLE et spécifiez le nom de la table entre guillemets qu'il créera la table avec le nom exact que vous spécifiez (non seulement le cas mais aussi la sémantique - de cette façon vous pouvez même créer une table nommée TABLE) :

CREATE TABLE "TeSt" ( id int PRIMARY KEY NOT NULL )

donnera lieu à un tableau TeSt8 .

CREATE TABLE TeSt2 ( id int PRIMARY KEY NOT NULL )

donnera lieu à un tableau test2 .

Ainsi, pour interroger la table "TeSt", vous devrez exécuter SELECT * FROM "TeSt" ( no SELECT * FROM TeSt ).

Ainsi, si vous créez une table avec CREATE TABLE "SAMPLE" vous devez spécifier @Table(name="\"SAMPLE\"") afin de le faire fonctionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X