23 сентября 2012 г.

Hibernate: чтение данных из postgres

Предположим, что у нас есть базе данных postgres есть таблица messages, состоящая всего из двух столбцов: bigint id, varchar(100) msg_text. О том, как подключиться к БД при помощи datasource, мы уже говорили ранее. Для того, чтобы автоматически помещать данные из этой таблицы в поля нашего класса, он должен выглядеть следующим образом:

@Entity
@Table(name = "messages")
public class MessageEntity {
Обычный класс размечается специальными аннотациями. @Entity говорит о том, что данный класс является сущностью, которая хранит данные, полученные из БД. @Table позволяет указать имя соответствующей таблицы. Обратите внимание, имя класса и имя таблицы могут быть разными - в этом проявляется гибкость использования аннотаций.

Далее следуют поля класса, которые также размечены аннотациями. Тип поля выбирается соответственно типу поля в таблице. bigint в postgres - это Long в java. Обратите внимание, что для id-поля в классе можно использовать только те типы, которые допускают null-значения. Это связано с тем, что при создании новой сущности id не должно иметь значение - Hibernate сам присвоит его при сохранении объекта в таблицу. Модификатор доступа для полей обязательно должен быть protected - это ограничение, накладываемое Hibernate.
@Id
@SequenceGenerator(name = "message_id_generator", sequenceName = "message_id_seq", initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "message_id_generator")
@Column(name = "id")
protected Long id;
Аннотация @Id показывает, что именно это поле будет хранить идентификатор записи. @SequenceGenerator задаёт sequence в postgres, который будет генерировать значения для этого поля. sequenceName - это название в самом postgres, тогда как name - имя внутри Hibernate, используемое в следующей аннотации @GeneratedValue. Наконец аннотация @Column задаёт имя поля в таблице. Опять же не обязательно должно совпадать с именем поля в нашем классе.

@Column(name = "msg_text", length = 100)
protected String messageText;

Второе поля будет содержать сам текст сообщения. Поэтому тип у него - String. Аннотация @Column задаёт имя соответствующего столбца в таблице и максимальную длину текста. Указывать параметр length у @Column рекомендуется для любого текстового поля. Это будет полезно не только для проверки длины текста в процессе работы программы, но и, например, при генерации скрипта создания таблицы на основе данной сущности. Такая возможность имеется, но это тема отдельного поста.

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getMessageText() {
return messageText;
}

public void setMessageText(String messageText) {
this.messageText = messageText;
}

}

Наконец, добавляем геттеры и сеттера для обоих полей. Большинство IDE позволяют автоматизировать этот рутинный процесс.

Сама по себе такая сущность мало чего умеет. Как можно, например, получить все записи из таблицы? Для этого можно использовать именованный запрос. Поместим его перед определением класса.

@NamedQueries
({
    @NamedQuery
    (
    name = "getMessageList",
    query = "select m from MessageEntity m order by m.id desc"
    )
})
Аннотация @NamedQueries определяет множество именованных запросов. @NamedQuery - конкретный запрос, содержащий его имя и сам запрос. Обратите внимание, что, хоть запрос и похож на sql-запрос, но таковым не является. Вместо полей таблицы здесь используются поля нашей сущности, да и выборка производится из неё же. m - любое имя. В процессе работы Hibernate трансформирует этот запрос в родной запрос sql для конкретной БД. В это проявляется очередная гибкость Hibernate.


Всё, наша сущность готова. Теперь можно посмотреть её в деле.

В любом классе, где необходимо работать с БД, мы можем определить поле:


@PersistenceContext(name = "manager1")
private EntityManager entityManager;

manager1 - это значение из секции persistence-unit в файле persistence.xml.

Выборка всех сообщений с использованием нашего именованного запроса будет выглядеть вот так:
List<MessageEntity> messageList = (List<MessageEntity>) entityManager.createNamedQuery("getMessageList").getResultList();
В результате мы получим список сущностей, в каждой из которых будут содержаться значения полей id и msg_text из таблицы.

Комментариев нет:

Отправить комментарий