Pages

Saturday, November 8, 2014

JPA-маппинг коллекций элементов

Коллекция элементов - это коллекция объектов базовых типов (например, String) или встроенных объектов.

Рассмотрим маппинг таких коллекций.

Музыкальный исполнитель может иметь псевдонимы и события, которые с ним связаны.

Создадим базу данных jpa_element_collections_mappings_tutorial и таблицы artists, aliases и events:

Колонка artist_name таблицы artists хранит имена исполнителей.
Колонка artist_alias таблицы aliases хранит псевдонимы исполнителей.
Колонки event_year и event_description таблицы events хранят данные о важных событиях в жизни исполнителей.
Таблицы aliases и events имеют колонки artist_id для связи с таблицей artists.

Добавим данные об исполнителе - Кори Тейлоре из групп Slipknot и Stone Sour:
CREATE DATABASE jpa_element_collections_mappings_tutorial;
USE jpa_element_collections_mappings_tutorial;

CREATE TABLE artists (
artist_id INT PRIMARY KEY,
artist_name VARCHAR(30)
);

CREATE TABLE aliases (
artist_id INT,
artist_alias VARCHAR(30),
PRIMARY KEY (artist_id, artist_alias),
FOREIGN KEY (artist_id) REFERENCES artists (artist_id)
);

CREATE TABLE events (
artist_id INT,
event_year INT,
event_description VARCHAR(50),
PRIMARY KEY (artist_id, event_year, event_description),
FOREIGN KEY (artist_id) REFERENCES artists (artist_id)
);

INSERT INTO artists VALUES (1, 'Corey Taylor');

INSERT INTO aliases VALUES (1, '#8');
INSERT INTO aliases VALUES (1, 'The Great Big Mouth');
INSERT INTO aliases VALUES (1, 'Faith');
INSERT INTO aliases VALUES (1, 'The Sickness');
INSERT INTO aliases VALUES (1, 'Todd Tigger');
INSERT INTO aliases VALUES (1, 'The Boogie Knight');
INSERT INTO aliases VALUES (1, 'Neck');
INSERT INTO aliases VALUES (1, 'CMFT');
INSERT INTO aliases VALUES (1, 'Corey MF Taylor');

INSERT INTO events VALUES (1, 1973, 'Born');
INSERT INTO events VALUES (1, 1992, 'Joined Stone Sour');
INSERT INTO events VALUES (1, 1997, 'Joined Slipknot');

Для работы с данными таблицы events будем использовать встроенные объекты. Для этого:
  • создадим класс Event с полями year и description
  • добавим этим полям аннотацию @Column с указанием соответствующих им колонок таблицы event (т.е. event_year и event_description)
  • добавим классу Event аннотацию @Embeddable
package com.jpa.element.collections.mappings.tutorial.domain;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class Event {

    @Column(name = "event_year")
    private int year;

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

    public Event() {

    }

    public Event(int year, String description) {
        this.year = year;
        this.description = description;
    }

    @Override
    public String toString() {
        return "Event{" +
                "year=" + year +
                ", description='" + description + '\'' +
                '}';
    }
}

Создадим класс сущности Artist с полями id, name, aliases и events.
Поле aliases хранит псевдонимы исполнителя. Для того, чтобы их получать:
  • добавим полю aliases аннотацию @ElementCollection, которая используется с коллекциями базовых типов (как String) и встроенных объектов, а не других сущностей. В последнем случае нужно было бы использовать аннотации для маппинга отношений между сущностями
  • добавим аннотацию @CollectionTable с указанием таблицы, в которой хранятся псевдонимы (т.е. aliases), и колонки, которая является внешним ключом (т.е. artist_id)
  • добавим аннотацию @Column с указанием колонки таблицы aliases, в которой хранятся псевдонимы, т.е. artist_alias
Поле events - это коллекция встроенных объектов, поэтому аналогично:
  • добавим аннотацию @ElementCollection
  • добавим аннотацию @CollectionTable с указанием таблицы, в которой хранятся данные о событиях (т.е. events), и колонки, которая является внешним ключом (т.е. artist_id)
  • и больше ничего не добавляем, потому что Event - это не базовый тип и он уже имеет маппинг на таблицу events
package com.jpa.element.collections.mappings.tutorial.domain;

import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import java.util.List;

@Entity
@Table(name = "artists")
public class Artist {

    @Id
    @Column(name = "artist_id")
    private int id;

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

    @ElementCollection
    @CollectionTable(name = "aliases", joinColumns = @JoinColumn(name = "artist_id"))
    @Column(name = "artist_alias")
    private List<String> aliases;

    @ElementCollection
    @CollectionTable(name = "events", joinColumns = @JoinColumn(name = "artist_id"))
    private List<Event> events;

    public Artist() {

    }

    public Artist(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getAliases() {
        return aliases;
    }

    public void setAliases(List<String> aliases) {
        this.aliases = aliases;
    }

    public List<Event> getEvents() {
        return events;
    }

    public void setEvents(List<Event> events) {
        this.events = events;
    }

    @Override
    public String toString() {
        return "Artist{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Создадим класс ArtistService:
package com.jpa.element.collections.mappings.tutorial.service;

import com.jpa.element.collections.mappings.tutorial.domain.Artist;

import javax.persistence.EntityManager;

public class ArtistService {

    private EntityManager em;

    public ArtistService(EntityManager em) {
        this.em = em;
    }

    public Artist findArtist(int id) {
        return em.find(Artist.class, id);
    }
}


Добавим класс Artist в persistence unit в файле persistence.xml:
<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_2_0.xsd"
             version="2.0">

    <persistence-unit name="JpaElementCollectionsMappingsTutorial" transaction-type="RESOURCE_LOCAL">
        <class>com.jpa.element.collections.mappings.tutorial.domain.Artist</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url"
                      value="jdbc:mysql://localhost:3306/jpa_element_collections_mappings_tutorial"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root"/>
        </properties>
    </persistence-unit>

</persistence>

В методе main() класса JpaElementCollectionsTutorial создается объект типа ArtistService, вызывается метод для получения сущности Artist и выводится информация об исполнителе, его псевдонимах и событиях:
package com.jpa.element.collections.mappings.tutorial;

import com.jpa.element.collections.mappings.tutorial.domain.Artist;
import com.jpa.element.collections.mappings.tutorial.domain.Event;
import com.jpa.element.collections.mappings.tutorial.service.ArtistService;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class JpaElementCollectionsMappingsTutorial {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("JpaElementCollectionsMappingsTutorial");
        EntityManager em = emf.createEntityManager();
        ArtistService service = new ArtistService(em);

        System.out.println("--- Find artist ---");
        Artist artist = service.findArtist(1);
        System.out.println(String.format("Found: %s", artist));

        System.out.println("\nArtist aliases:");
        for (String alias : artist.getAliases()) {
            System.out.println(alias);
        }

        System.out.println("\nArtist events:");
        for (Event event : artist.getEvents()) {
            System.out.println(event);
        }

        em.close();
        emf.close();
    }
}

Запустим метод main():
--- Find artist ---
Found: Artist{id=1, name='Corey Taylor'}

Artist aliases:
#8
CMFT
Corey MF Taylor
Faith
Neck
The Boogie Knight
The Great Big Mouth
The Sickness
Todd Tigger

Artist events:
Event{year=1973, description='Born'}
Event{year=1992, description='Joined Stone Sour'}
Event{year=1997, description='Joined Slipknot'}

Приложение вывело информацию об исполнителе, его псевдонимах и событиях, а значит мы успешно сделали маппинг коллекций элементов.

Структура проекта:



























Исходный код созданного приложения доступен по ссылке https://code.google.com/p/jpa-element-collections-mappings-tutorial/.

Рекомендуемые посты:

No comments:

Post a Comment