'Hibernate - Map View to Entity - view is not mapped [SELECT la FROM ListAgent la]

In an effort to power an autocomplete, I resolved to map a PostgreSQL view. I followed a tutorial for this.

It seems that it does not work at all : I've always a java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: ListAgent is not mapped [SELECT la FROM ListAgent la].

However, I have tried many things to solve my problem:

  • Map of a view in an entity (as in the tutorial);
  • Using a @Subselect;
  • Creation of a materialized view and its unique index;
  • Setting exclude-unlisted-classes to false (persistence.xml);
  • deactivation of JPA validator in build in Eclipse (due to problems with @Entity);
  • Added constructors and setters (may be unnecessarily)

No success: always the same answer.

The Test-case

package fr.gouv.finances.douane.cotes.dao.agent;

import static org.junit.Assert.assertEquals;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

    /**
     * Tests unitaires de la classe PasswordDAOImpl
     * 
     * @author VANDEKERKHOVE
     * @version 0.0.1.SNAPSHOT
     */
    public class AgentDAOImplTest {
        
        // Stateless
        private AgentDAOImpl dao;
        
        // Emulation du serveur Wildfly
        private EntityManager em;
        private static EntityManagerFactory emf;

        @SuppressWarnings("unused")
        private List<?> las;
        
        /**
         * Initialisation de l'environnement de test
         * @throws java.lang.Exception
         */
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
            // Factory construite une fois
            emf = Persistence.createEntityManagerFactory("cote-s-ejbTest");
        }
        
        /**
         * Remise en etat de l'environnement de test
         * @throws java.lang.Exception
         */
        @AfterClass
        public static void tearDownAfterClass() throws Exception {
            // Suppression de la factory
            emf.close();
            emf = null; 
        }
        
        /**
         * Initialisation avant chaque test
         * @throws java.lang.Exception
         */
        @Before
        public void setUp() throws Exception {
            // Au debut de chaque testcase
            em = emf.createEntityManager();
            em.getTransaction().begin();
            
            // Stateless
            dao = new AgentDAOImpl();
            dao.setEm(em);
        }
        
        /**
         * Reset après chaque test
         * @throws java.lang.Exception
         */ 
        @After
        public void tearDown() throws Exception {
            // A la fin de chaque test
            em.getTransaction().commit();
            em.close();
            
            // Fin du Stateless
            dao.setEm(null);
            dao = null;
        }
        
        //=========================
        // Tests proprements dits
        //=========================
        @Test
        public void test() {
            List<ListAgent> las = em.createQuery("SELECT la FROM ListAgent la", ListAgent.class).getResultList();
            
            ListAgent la_enr = las.get(0);
            
            assertEquals("FROC Christian", la_enr.getName());
        }
}

The class ListAgent

package fr.gouv.finances.douane.cotes.dao.agent;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect;

/**
 * Classe de requete pour la vue "l_agents"
 * 
 * @author Jean Paul Vandekerkhove
 * @version 0.0.2.SNAPSHOT
 */
@Entity
@Immutable
@Subselect("SELECT a.a_id AS id,\r\n" + 
        "    ((btrim((a.a_nom)::text) || ' '::text) || btrim((a.a_prenom)::text)) AS name\r\n" + 
        "   FROM agent a\r\n" + 
        "  WHERE ((a.a_actif = true) OR ((a.a_actif = false) AND (a.a_datesuppression >= CURRENT_DATE)));")
//@Table(name="l_agents", schema="cotes_admin")
public class ListAgent {
    
    //=========================
    // Attributs
    //========================= 
    @Id
    @Column(name="id", updatable = false, nullable = false)
    private Long id;
    
    @Column(name="name")
    private String name;

    //=========================
    //     Constructeurs
    //=========================     
    /**
     * Constructeur vide
     */
    public ListAgent() {
        super();
    }   
    
    /**
     * Constructeur complet
     * 
     * @param id - Identifiant de l'agent
     * @param name - nom-prénom de l'agent
     */
    public ListAgent(Long id, String name) {
        super();
        this.id = id;
        this.name = name;
    }   

    //=========================
    //    Getters et Setters
    //=========================
    /**
     * Retourne l'identifiant de l'Agent
     * @return id - identifiant de l'Agent
     */
    public Long getId() {
        return id;
    }

    /**
     * MaJ de l'Identifiant de l'Agent
     * @param id - Identifiant de l'agent
     */
    public void setId(Long id) {
        this.id = id;
    }
    
    /**
     * Retourne l'identité complete de l'Agent
     * @return name - nom-prénom de l'Agent
     */
    public String getName() {
        return name;
    }

    /**
     * MaJ de l'identité complete de l'Agent
     * @param name - nom-prénom de l'Agent
     */
    public void setName(String name) {
        this.name = name;
    }
}

The POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <parent>
    <groupId>fr.gouv.finances.douane.cote-s</groupId>
    <artifactId>cote-s</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  
  <artifactId>cote-s-ejb</artifactId>
  <packaging>ejb</packaging>
   
  <dependencies>
    
    <dependency>
        <groupId>org.jboss.spec.javax.ejb</groupId>
        <artifactId>jboss-ejb-api_3.2_spec</artifactId>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.3.15.Final</version><!--$NO-MVN-MAN-VER$-->
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <scope>provided</scope>
    </dependency>
    
    <!-- Tests -->
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.2.12</version>
        <scope>test</scope>
    </dependency>
    
  </dependencies>
  
  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
            
            <!-- package EJB 3 -->

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <ejbVersion>3.2</ejbVersion>
                    <generateClient>true</generateClient>
                    <clientIncludes>
                        <clientInclude>**/*.class</clientInclude>
                    </clientIncludes>
                    <clientExcludes>
                        <clientExclude>**/*Bean.class</clientExclude>
                    </clientExcludes>
                </configuration>
            </plugin>
            
        </plugins>
    </build>
    
</project>

The main software used (all at the technical level)

  • Eclipse 2020-06;
  • OpenJDK Red Hat 11;
  • Wildfly 19.1;
  • PostgreSQL 11;

The persistence.xml (normal)

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd" version="2.2">
    <persistence-unit name="cote-s-ejb" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>    
        <jta-data-source>java:/CotesDS-ds</jta-data-source>
        <class>fr.gouv.finances.douane.cotes.dao.agent.Agent</class>
        <class>fr.gouv.finances.douane.cotes.dao.grade.Grade</class>
        <class>fr.gouv.finances.douane.cotes.dao.service.Service</class>
        <class>fr.gouv.finances.douane.cotes.dao.droit.Droit</class>
        <class>fr.gouv.finances.douane.cotes.dao.droitAgent.DroitAgent</class>
        <class>fr.gouv.finances.douane.cotes.dao.cycleCourt.CycleCourt</class>
        <class>fr.gouv.finances.douane.cotes.dao.desiderata.Desiderata</class>
        <class>fr.gouv.finances.douane.cotes.dao.disponibilite.Disponibilite</class>
        <class>fr.gouv.finances.douane.cotes.dao.mvtCyclecourt.Mvtcyclecourt</class>
        <class>fr.gouv.finances.douane.cotes.dao.mvtDesiderata.Mvtdesiderata</class>
        <class>fr.gouv.finances.douane.cotes.dao.password.Password</class>
        <class>fr.gouv.finances.douane.cotes.dao.activite.Activite</class>
        <class>fr.gouv.finances.douane.cotes.dao.coteService.CoteService</class>
        <class>fr.gouv.finances.douane.cotes.dao.quantieme.Quantieme</class>
        <class>fr.gouv.finances.douane.cotes.dao.sdf.Sdf</class>
        <class>fr.gouv.finances.douane.cotes.dao.vacation.Vacation</class>
        <class>fr.gouv.finances.douane.cotes.dao.mvtArtt.Mvtartt</class>
        <class>fr.gouv.finances.douane.cotes.dao.typeConge.Typeconge</class>
        <class>fr.gouv.finances.douane.cotes.dao.absences.Absence</class>
        <class>fr.gouv.finances.douane.cotes.dao.prevision.Prevision</class>
        <class>fr.gouv.finances.douane.cotes.dao.recuperation.Recuperation</class>
        <class>fr.gouv.finances.douane.cotes.dao.conges.Conges</class>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/>
            <property name="hibernate.default_schema" value="cotes_admin"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>          
            <!-- JBoss -->
            <property name="jboss.entity.manager.jndi.name" value="java:/emCotes"/>
            <property name="jboss.entity.manager.factory.jndi.name" value="java:/emCotesFactory"/>
        </properties>
    </persistence-unit>       
</persistence>

The persistence.xml (tests)

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd" version="2.2">
    <persistence-unit name="cote-s-ejbTest" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>    
        <class>fr.gouv.finances.douane.cotes.dao.agent.Agent</class>
        <class>fr.gouv.finances.douane.cotes.dao.grade.Grade</class>
        <class>fr.gouv.finances.douane.cotes.dao.service.Service</class>
        <class>fr.gouv.finances.douane.cotes.dao.droit.Droit</class>
        <class>fr.gouv.finances.douane.cotes.dao.droitAgent.DroitAgent</class>
        <class>fr.gouv.finances.douane.cotes.dao.cycleCourt.CycleCourt</class>
        <class>fr.gouv.finances.douane.cotes.dao.desiderata.Desiderata</class>
        <class>fr.gouv.finances.douane.cotes.dao.disponibilite.Disponibilite</class>
        <class>fr.gouv.finances.douane.cotes.dao.mvtCyclecourt.Mvtcyclecourt</class>
        <class>fr.gouv.finances.douane.cotes.dao.mvtDesiderata.Mvtdesiderata</class>
        <class>fr.gouv.finances.douane.cotes.dao.password.Password</class>
        <class>fr.gouv.finances.douane.cotes.dao.activite.Activite</class>
        <class>fr.gouv.finances.douane.cotes.dao.coteService.CoteService</class>
        <class>fr.gouv.finances.douane.cotes.dao.quantieme.Quantieme</class>
        <class>fr.gouv.finances.douane.cotes.dao.sdf.Sdf</class>
        <class>fr.gouv.finances.douane.cotes.dao.vacation.Vacation</class>
        <class>fr.gouv.finances.douane.cotes.dao.mvtArtt.Mvtartt</class>
        <class>fr.gouv.finances.douane.cotes.dao.typeConge.Typeconge</class>
        <class>fr.gouv.finances.douane.cotes.dao.absences.Absence</class>
        <class>fr.gouv.finances.douane.cotes.dao.prevision.Prevision</class>
        <class>fr.gouv.finances.douane.cotes.dao.recuperation.Recuperation</class>
        <class>fr.gouv.finances.douane.cotes.dao.conges.Conges</class>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/>
            <property name="hibernate.default_schema" value="cotes_admin"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/cotes"/>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
            <property name="hibernate.connection.username" value="cotes_admin"/>
            <property name="hibernate.connection.password" value="cotes_admin"/>            
        </properties>
    </persistence-unit>       
</persistence>

Thank you in advance for your Help.

Best Regards



Solution 1:[1]

I put the pseudo-entity in the persistence.xml, and reset the exclude-unlisted-classes to true. Finaly, After removing the "::text)", the ";" final, and readjusted the parentheses, the test changed to green. The question is a priori closed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jpvandekerkhove