Обзор Hibernate Criteria API

Одним из способов манипулирования объектом и транслирования его в таблицу базы данных (БД) является Criteria API, который позволяет создавать запросы с критериями программным методом. Наиболее значимые области применения Criteria API :

  • получение значение агрегатных функций типа sum(), min(), max() и т.д.;
  • извлечения данных только из выбранных колонок с использованием ProjectionList;
  • соединение нескольких таблиц для join запросов с использованием методов createAlias(), setFetchMode() и setProjection();
  • выборка результатов согласно условиям с использованием метода add(), параметрами которого являются ограничения (Restrictions);
  • определение порядка сортировки добавлением к критерию метода addOrder().

Для создания объекта org.hibernate.Criteria используется метод createCriteria интерфейса сессии Session, которому в качестве параметра необходимо передать сущность. Следующий код формирует объект Criteria для выполнения транзакций с сущностью разработчика Developer.

Criteria criteria = session.createCriteria (Developer.class);

Чтение данных

Следующий код позволяет прочитать данные и сформировать коллекцию. Чтобы прочитать определенное количество записей необходимо использовать метод setMaxResults (int) объекта Criteria. Метод setFirstResult (int) определяет первую запись. Т.е. данные методы позволяют определить параметры OFFSET, LIMIT, используемые в SQL-запросах некоторых типов БД.

Criteria criteria = session.createCriteria (Developer.class);
criteria.setFirstResult(5);
criteria.setMaxResults (10);

List<Developer> developers = criteria.list();

Сортировка данных в запросе Criteria

Для сортировки данных в запросе используется метод addOrder, которому в качестве параметра необходимо передать порядок сортировки (Order) :

// Сортировка набора по возрастанию значения поля firstName
Criteria criteria = session.createCriteria (Developer.class)
                           .addOrder(Order.asc("firstName"));
						   
// Сортировка набора по убыванию значения поля firstName
criteria.addOrder(Order.desc("firstName");

Ограничения данных в запросе Criteria

Для ограничения/фильтрации объектов набора используется параметр Restrictions.[eq | lt | le | gt | ge | like | between | isNotNull | isNull]. Следующий код демонстрирует использование в критерии параметра Restrictions.


// список разработчиков с опытом разработки больше или равен 3
Criteria criteria = session.createCriteria(Developer.class)
                           .add(Restrictions.ge("experience", 3);
					 
// список разработчиков, у которых login начинается с 'serg'
Criteria criteria = session.createCriteria(Developer.class)
                           .add(Restrictions.like("login", "serg%");
					 
// список разработчиков, у которых birth_date is null
Criteria criteria = session.createCriteria(Developer.class)
                           .add(Restrictions.isNull("birth_date");
   
// список разработчиков, у которых birth_date is not null:
Criteria criteria = session.createCriteria(Developer.class)
                           .add(Restrictions.isNotNull("birth_date");

Пример использования org.hibernate.Criteria

Рассмотрим пример использования org.hibernate.Criteria и сущности Developer. В примере создадим и запишем новые сущности в базу данных, после чего извлечем определенные записи. При описании сущности будем использовать аннотации. По сути, это модифицированный пример использования Sequence для генерирования идентификаторов записей в Hibernate, описанный здесь. Поэтому ниже будут представлены только используемые методы, связанные с org.hibernate.Criteria. Сначала определим объекты базы данных.

Таблица и генератор запросов

В примере потребуется таблица DEVELOPERS и генератор последовательностей SEQ_DEVELOPER в схеме SCOTT.

CREATE TABLE SCOTT.DEVELOPERS
(
   ID          INT NOT NULL,
   FIRST_NAME  VARCHAR2(64) default NULL,
   LAST_NAME   VARCHAR2(64) default NULL,
   SPECIALTY   VARCHAR2(64) default NULL,
   EXPERIENCE  INT default NULL,
   SALARY      INT default NULL,
   CONSTRAINT pk_DEVELOPER_ID PRIMARY KEY (id),
);

create sequence SCOTT.SEQ_DEVELOPER
  minvalue 1
  start with 5
  increment by 1
  cache 2;

Листинг сущности Developer

При описании сущности (методы set/get не отображены) используем аннотации. Подробнее об аннотациях, используемых при описании сущности, представлено здесь.

@Entity
@Table(name = "developers")
public class Developer 
{
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,
                    generator="dev_seq")
    @SequenceGenerator(name="dev_seq", 
                       sequenceName="SEQ_DEVELOPER",
                       allocationSize=5)
    @Column(name="id")
    private  int id;

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

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

    @Column
    private  String  specialty;
    @Column
    private  int     experience;
    @Column
    private  int     salary;

    public Developer(int id, String firstName, 
                     String lastName, String specialty,
                     int experience, int salary) 
    {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.specialty = specialty;
        this.experience = experience;
        this.salary = salary;
    }
    public Developer() {}

    // get/set
	
    @Override
    public String toString() {
        return "Developer [id=" + id + ", firstName=" + firstName
                + ", lastName=" + lastName + ", specialty=" + specialty
                + ", experience=" + experience + ", salary=" + salary + "]";
    }
}

Сохранение новых записей в БД

Для сохранения записей в таблице БД определяем массив DEVELOPERS и два метода. Первый метод addDevelopers в цикле перебирает массив данных и вызывает второй метод addDeveloper, который формирует объект Developer и сохраняет его в БД.

private  Session  session = null;

private  final  String[][]  DEVELOPERS = {
   {"Сергей", "Ветров"      , "Java Developer",  "6", "2400"},
   {"Олег"  , "Мантров"     , "C++ Developer" , "10", "2300"},
   {"Остап" , "Бендер"      , "C# Developer"  ,  "5", "2200"},
   {"Киса"  , "Воробьянинов", "PHP Developer" ,  "4", "2500"}
};

. . .

private void addDevelopers()
{
    Transaction transaction = null;
    transaction = session.beginTransaction();
        
    for (int i = 0; i < DEVELOPERS.length; i++) {
        addDeveloper(DEVELOPERS[i][0], 
                     DEVELOPERS[i][1],
                     DEVELOPERS[i][2], 
                     Integer.valueOf(DEVELOPERS[i][3]), 
                     Integer.valueOf(DEVELOPERS[i][4]));
    }
    transaction.commit();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private Integer addDeveloper(String firstName, String lastName,
                  String specialty, int experience, int salary)
{
    Integer developerId = null;

    Developer developer = new Developer();
    developer.setFirstName (firstName );
    developer.setLastName  (lastName  );
    developer.setExperience(experience);
    developer.setSpecialty (specialty );
    developer.setSalary    (salary    );
    developerId = (Integer) session.save(developer);

    return developerId;
}

При выполнении метода addDevelopers в консоль приложения будет выведена информация, представленная ниже. Hibernate подготавливает один запрос получения идентификатора записи и для каждой записи отдельный SQL-запрос вставки.


Hibernate: select SEQ_DEVELOPER.nextval from dual
Hibernate: insert into developers (experience, FIRST_NAME, LAST_NAME, 
                                   salary, specialty, id) 
                          values (?, ?, ?, ?, ?, ?)
Hibernate: insert into developers (experience, FIRST_NAME, LAST_NAME, 
                                   salary, specialty, id) 
                          values (?, ?, ?, ?, ?, ?)
Hibernate: insert into developers (experience, FIRST_NAME, LAST_NAME, 
                                   salary, specialty, id) 
                          values (?, ?, ?, ?, ?, ?)
Hibernate: insert into developers (experience, FIRST_NAME, LAST_NAME, 
                                   salary, specialty, id) 
                          values (?, ?, ?, ?, ?, ?)
 

Фильтрация записей

Метод listDevelopers позволяет прочитать записи разработчиков, у которых опыт работы превышает значение min_experience. В методе формируется объект criteria, которому добавляется условие (ограничение Restrictions) с параметром "experience" и значением min_experience.

public void listDevelopers(final int min_experience)
{
    Transaction transaction = session.beginTransaction();

    Criteria criteria = session.createCriteria(Developer.class);
    criteria.add(Restrictions.gt("experience", min_experience));

    List<Developer> developers = criteria.list();

    for (Developer developer : developers)
        System.out.println(developer);

    transaction.commit();
}

В результате выполнения метода listDevelopers в консоль будет выведена информация, представляющая сформированный hibernate запрос и прочитанные данные для значение min_experience равное 5 :


Hibernate: select this_.id as id1_0_0_, 
                  this_.experience as experience2_0_0_, 
                  this_.FIRST_NAME as FIRST_NAME3_0_0_, 
                  this_.LAST_NAME as LAST_NAME4_0_0_,
                  this_.salary as salary5_0_0_,
                  this_.specialty as specialty6_0_0_ 
              from developers this_ 
                  where this_.experience > ?

Developer [id=45, firstName=Сергей, lastName=Ветров, 
           specialty=Java Developer, experience=6, salary=2400]
Developer [id=46, firstName=Олег, lastName=Мантров, 
          specialty=C++ Developer, experience=10, salary=2300]
 

Выполнение функции суммирования

Как было описано выше Criteria можно использовать для выполнения агрегированных функций. Следующий метод totalSalary позволяет просуммировать заработок всех разработчиков. Для этого используется метод setProjection критерия, параметр которого определяет агрегированную функцию. Метод list вернет набор из одной записи, значение которой определяет результат выполненной функции.

public void totalSalary() 
{
    Transaction transaction = session.beginTransaction();

    Criteria criteria = session.createCriteria(Developer.class);
    criteria.setProjection(Projections.sum("salary"));

    List<Integer> totalSalary = criteria.list();
    System.out.println("Заработок разработчиков : " + 
                                 totalSalary.get(0));

    transaction.commit();
}

Выполнение метода выведет следующую информацию в консоль : SQL-запрос суммирования значения поля salary и значение :


Hibernate: select sum(this_.salary) as y0_ from developers this_
Заработок разработчиков : 9400
 

Скачать пример

Исходный код примера в виде проекта Eclipse hibernate-criteria.zip, включающий все необходимые библиотеки hibernate, можно скачать здесь (8.216 Mб).

  Рейтинг@Mail.ru