Can we define all the Named Queries at one place like some property file instead of writing in the entity class

10.7k views Asked by At

How to Define All Named Queries in One place (like class) instead of writing the NamedQuery in top of Entity class.

For Example i have a base class. In this class i can define all named queries.

Base.java

@Entity
@NamedQueries({
    @NamedQuery(name="Student.findAll", query="SELECT s FROM Student s"),
    @NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e")})    
class Base {

}

Assume now i have two entities like Student and Employee. Now i want to access the Named query from Base class. It is possible to access. If is possible then how.

class Employee {

}

class Student {

}

In employee class, Student i want to access the named query from Base class. It is possible. If it is possible how i can access.

5

There are 5 answers

1
Predrag Maric On BEST ANSWER

We did a similar thing on one project. We had one entity that contained all of our named queries and (as @jimfromsa already said) they are accessible to your code wherever you need them because you are calling them by their unique name.

@Entity
@NamedQueries({
    @NamedQuery(name="Student.findAll", query="SELECT s FROM Student s"),
    @NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e"), 
    ...
    @NamedQuery(name="SomeEntity.someQuery", query="SELECT se FROM SomeEntity se")
})
public class NamedQueryHolder implements Serializable {
    // entity needs to have an id
    @Id
    private Integer id;

    // getter and setter for id
}

Note that this entity doesn't need to be mapped to an existing table, as long as you don't use it anywhere in the code. At least this approach worked with EclipseLink, never tried it with Hibernate.

In your case, if you don't want this extra query holder entity, you can put all named queries in Base class and it will work. However, I don't think it is a good idea to access named queries from your entity classes, they are called POJOs for a reason. Then again, it is all a matter of design (take a look at Anemic Domain Model).

0
Ranga Reddy On

Finally MySelf i found the Answer.

Base.java

 @Entity
    @NamedQueries({ @NamedQuery(name="Employee.findAll", query = "SELECT e FROM Employee e"), 
                    @NamedQuery(name="Student.findAll", query = "SELECT s FROM Student s") })

    public class Base {
        @Id
        private long id;

    }

Employee.java

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="Employee")
public class Employee implements Serializable {
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

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

    @Column(name="salary")
    private float salary;

    // Setters and getters
}

Student.java

 import java.io.Serializable;        
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;

@Entity
@Table(name="Student")
public class Student implements Serializable {
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

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

    @Column(name="salary")
    private float salary;

    // setters and getters
}

Application.java

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

public class Application {
    private static String PERSISTENCE_UNIT_NAME = "EmployeeService";
    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        EntityTransaction entityTransaction = entityManager.getTransaction();

        // Before executing this query insert some records

        Query query = entityManager.createNamedQuery("Employee.findAll", Employee.class);
        query.setFirstResult(0);
        query.setMaxResults(10);

        @SuppressWarnings("unchecked")
        List<Employee> employees = query.getResultList();
        System.out.println(" \n "+employees);

        /*Student student = new Student();
        student.setName("Ranga");
        student.setSalary(15000);
        try {       
            entityTransaction.begin();
            entityManager.persist(student);
            System.out.println("Student Information: "+student);
            entityTransaction.commit();         
        } catch(PersistenceException ex) {          
            entityTransaction.rollback();
        }*/

        // Before executing this query insert some records

        query = entityManager.createNamedQuery("Student.findAll", Student.class);
        query.setFirstResult(0);
        query.setMaxResults(10);

        @SuppressWarnings("unchecked")
        List<Student> students = query.getResultList();
        System.out.println(" \n "+students);        

    }
}
0
Fabien M On

Nowadays there are no more xml files, just annotations. But you can't use annotations to define all your named queries in the same location, unless you create some "fake" entity, which might not be portable across all JPA implementations, or will screw something up one day or another down the road.

The easiest is to create them one by one using the EntityManager/EntityManagerFactory at some point at the startup of your application (or at least when your EntityManager is created). Just somewhat paraphrasing Ranga Reddy above.

    static final String QUERY_GET_BY_USERNAME = "Customer.getByUsername";
    static final String QUERY_COUNT = "Customer.count";


    // make it so this method is called when the entity manager is created, or at least before any named query is called.<<
    protected void createNamedQueries(EntityManager em) {
        EntityManagerFactory emf = em.getEntityManagerFactory();

        emf.addNamedQuery(QUERY_GET_BY_USERNAME, em.createQuery("from Customer where lower(login) = lower(:username)", Customer.class));
        emf.addNamedQuery(QUERY_COUNT, em.createQuery("select count(c) from Customer c", Long.class));
        // etc...
    }

and later during your business function calls:

        TypedQuery<Customer> query = entityManager.createNamedQuery(QUERY_GET_BY_USERNAME, Customer.class);
        List<Customer> customers = query.setParameter("username", "johndoe").getResultList();

0
jimfromsa On

Named queries are found by hibernate so they should be available to the hibernate session no matter which entity they are declared in.

@Entity
@NamedQueries({
    @NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e")
     })
class Employee {

}

@Entity
@NamedQueries({
    @NamedQuery(name="Student.findAll", query="SELECT s FROM Student s"),
    })
class Student {

}

Then you would be able to use them by using the hibernate session.

SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();

//HQL Named Query Example
Query query = session.getNamedQuery("Student.findAll");
List<Student> empList = query.list();
for Student student : studentList) {
    System.out.println("List of Students::" + student.getId() + ","
            + student.getAddress().getCity());
}

// rolling back to save the test data
tx.commit();
// closing hibernate resources
sessionFactory.close();

See http://www.journaldev.com/3451/hibernate-named-query-example-tutorial-namedquery-annotation-join-hql-native-sql for more info on named queries with hibernate se

0
ivan.sim On

If you don't want the named queries to be mingled in your entity codes, you can store them in separate XML files like this:

employee.xml:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm  
                 http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">

  <package>mypersistenceunit</package>

  <named-query name="Employee.findAll">
    <query><![CDATA[SELECT e FROM Employee e]]></query>
  </named-query>
</entity-mappings>

student.xml:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm  
                 http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">

  <package>mypersistenceunit</package>

  <named-query name="Student.findAll">
    <query><![CDATA[SELECT e FROM Employee e]]></query>
  </named-query>
</entity-mappings>

Then you can include them in your persistence.xml like this:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence     
             http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">

  <persistence-unit name="some-persistence-unit">
    <jta-data-source>java:/someDS</jta-data-source>

    <!-- Named JPQL queries per entity, but other organization is possible  -->
    <mapping-file>META-INF/employee.xml</mapping-file>
    <mapping-file>META-INF/student.xml</mapping-file>
  </persistence-unit>
</persistence>

Now you should be able to call these named queries from your Employee and Student classes by invoking EntityManager.createNamedQuery().

This way, you don't have to create a Base class just to store queries.