Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lect17-hibernate-orm / more / hibernate_reference.pdf
Скачиваний:
93
Добавлен:
18.03.2015
Размер:
2 Мб
Скачать
☆

Part 2 - Mapping associations

);

}

}

A new listEvents() method is also added:

private List listEvents() {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();

List result = session.createQuery("from Event").list();

session.getTransaction().commit();

return result;

}

Here, we are using a Hibernate Query Language (HQL) query to load all existing Event objects from the database. Hibernate will generate the appropriate SQL, send it to the database and populate Event objects with the data. You can create more complex queries with HQL. See

Chapter 16, HQL: The Hibernate Query Language for more information.

Now we can call our new functionality, again using the Maven exec plugin: mvn exec:java -

Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="list"

1.2. Part 2 - Mapping associations

So far we have mapped a single persistent entity class to a table in isolation. Let's expand on that a bit and add some class associations. We will add people to the application and store a list of events in which they participate.

1.2.1. Mapping the Person class

The first cut of the Person class looks like this:

package org.hibernate.tutorial.domain;

public class Person {

private Long id; private int age;

private String firstname; private String lastname;

public Person() {}

// Accessor methods for all properties, private setter for 'id'

}

Save this to a file named src/main/java/org/hibernate/tutorial/domain/Person.java

13

Chapter 1. Tutorial

Next, create the new mapping file as src/main/resources/org/hibernate/tutorial/domain/

Person.hbm.xml

<hibernate-mapping package="org.hibernate.tutorial.domain">

<class name="Person" table="PERSON"> <id name="id" column="PERSON_ID">

<generator class="native"/>

</id>

<property name="age"/> <property name="firstname"/> <property name="lastname"/>

</class>

</hibernate-mapping>

Finally, add the new mapping to Hibernate's configuration:

<mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>

<mapping resource="org/hibernate/tutorial/domain/Person.hbm.xml"/>

Create an association between these two entities. Persons can participate in events, and events have participants. The design questions you have to deal with are: directionality, multiplicity, and collection behavior.

1.2.2. A unidirectional Set-based association

By adding a collection of events to the Person class, you can easily navigate to the events for a particular person, without executing an explicit query - by calling Person#getEvents. Multi-valued associations are represented in Hibernate by one of the Java Collection Framework contracts; here we choose a java.util.Set because the collection will not contain duplicate elements and the ordering is not relevant to our examples:

public class Person {

private Set events = new HashSet();

public Set getEvents() { return events;

}

public void setEvents(Set events) { this.events = events;

}

}

14

Working the association

Before mapping this association, let's consider the other side. We could just keep this unidirectional or create another collection on the Event, if we wanted to be able to navigate it from both directions. This is not necessary, from a functional perspective. You can always execute an explicit query to retrieve the participants for a particular event. This is a design choice left to you, but what is clear from this discussion is the multiplicity of the association: "many" valued on both sides is called a many-to-many association. Hence, we use Hibernate's many-to-many mapping:

<class name="Person" table="PERSON"> <id name="id" column="PERSON_ID">

<generator class="native"/>

</id>

<property name="age"/> <property name="firstname"/> <property name="lastname"/>

<set name="events" table="PERSON_EVENT"> <key column="PERSON_ID"/>

<many-to-many column="EVENT_ID" class="Event"/> </set>

</class>

Hibernate supports a broad range of collection mappings, a set being most common. For a many- to-many association, or n:m entity relationship, an association table is required. Each row in this table represents a link between a person and an event. The table name is decalred using the table attribute of the set element. The identifier column name in the association, for the person side, is defined with the key element, the column name for the event's side with thecolumn attribute of the many-to-many. You also have to tell Hibernate the class of the objects in your collection (the class on the other side of the collection of references).

The database schema for this mapping is therefore:

 

_____________

 

 

__________________

 

 

 

 

|

 

|

|

 

|

 

_____________

 

|

EVENTS

|

|

PERSON_EVENT

|

|

 

|

|_____________|

|__________________|

|

PERSON

|

|

 

|

|

 

|

|_____________|

| *EVENT_ID

| <--> |

*EVENT_ID

|

|

 

|

|

EVENT_DATE

|

|

*PERSON_ID

| <--> | *PERSON_ID

|

|

TITLE

|

|__________________|

|

AGE

|

|_____________|

 

 

 

|

FIRSTNAME

|

 

 

 

 

 

 

|

LASTNAME

|

 

 

 

 

 

 

|_____________|

 

 

 

 

 

 

 

 

 

1.2.3. Working the association

Now we will bring some people and events together in a new method in EventManager:

15

Chapter 1. Tutorial

private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId); Event anEvent = (Event) session.load(Event.class, eventId); aPerson.getEvents().add(anEvent);

session.getTransaction().commit();

}

After loading a Person and an Event, simply modify the collection using the normal collection methods. There is no explicit call to update() or save(); Hibernate automatically detects that the collection has been modified and needs to be updated. This is called automatic dirty checking. You can also try it by modifying the name or the date property of any of your objects. As long as they are in persistent state, that is, bound to a particular Hibernate org.hibernate.Session, Hibernate monitors any changes and executes SQL in a write-behind fashion. The process of synchronizing the memory state with the database, usually only at the end of a unit of work, is called flushing. In our code, the unit of work ends with a commit, or rollback, of the database transaction.

You can load person and event in different units of work. Or you can modify an object outside of a org.hibernate.Session, when it is not in persistent state (if it was persistent before, this state is called detached). You can even modify a collection when it is detached:

private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction();

Person aPerson = (Person) session

.createQuery("select p from Person p left join fetch p.events where p.id = :pid")

.setParameter("pid", personId)

.uniqueResult(); // Eager fetch the collection so we can use it detached Event anEvent = (Event) session.load(Event.class, eventId);

session.getTransaction().commit();

// End of first unit of work

aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached

// Begin second unit of work

Session session2 = HibernateUtil.getSessionFactory().getCurrentSession(); session2.beginTransaction();

session2.update(aPerson); // Reattachment of aPerson

session2.getTransaction().commit();

}

16

Соседние файлы в папке more