1 The Seven Relationship The Seven Relationship Types Types Seven types of relationships can exist between Seven types of relationships can exist between entity beans. There are four types of entity beans. There are four types of cardinality: one-to-one, one-to-many, many-to- cardinality: one-to-one, one-to-many, many-to- one, and many-to-many. In addition, each one, and many-to-many. In addition, each relationship can be either unidirectional or relationship can be either unidirectional or bidirectional. bidirectional. These op These opt ions seem to yield eight possibilities, ions seem to yield eight possibilities, but if you think about it, you'll realize that but if you think about it, you'll realize that one-to-many and many-to-one bidirectional one-to-many and many-to-one bidirectional relationships are actually the same thing. relationships are actually the same thing. Thus, there are only seven distinct relationship Thus, there are only seven distinct relationship types. To understand relationships, it helps to types. To understand relationships, it helps to think about some simple examples: think about some simple examples:
90
Embed
1 The Seven Relationship Types Seven types of relationships can exist between entity beans. There are four types of cardinality: one-to- one, one-to-many,
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
11
The Seven Relationship TypesThe Seven Relationship Types
Seven types of relationships can exist between entity Seven types of relationships can exist between entity beans. There are four types of cardinality: one-to-beans. There are four types of cardinality: one-to-one, one-to-many, many-to-one, and many-to-many. one, one-to-many, many-to-one, and many-to-many. In addition, each relationship can be either In addition, each relationship can be either unidirectional or bidirectional. unidirectional or bidirectional.
These opThese options seem to yield eight possibilities, but if ions seem to yield eight possibilities, but if you think about it, you'll realize that one-to-many and you think about it, you'll realize that one-to-many and many-to-one bidirectional relationships are actually many-to-one bidirectional relationships are actually the same thing. the same thing.
Thus, there are only seven distinct relationship types. Thus, there are only seven distinct relationship types. To understand relationships, it helps to think about To understand relationships, it helps to think about some simple examples:some simple examples:
The relationship between a cruise and a reservation.
Given a reservation, you want to be able to look up the cruise for which the reservation was made.
And given a particular cruise, you want to be able to look up all reservations. (Note that a many-to-one bidirectional relationship is just another perspective on the same concept.)
The relationship between a cruise and a ship. You want to be able to look up the ship that
will be used for a particular cruise, and many cruises share the same ship, though at different times.
It's less useful to look up the ship to see which cruises are associated with it, although if you want this capability, you can implement a many-to-one bidirectional relationship.
The relationship between a reservation and a cabin. It's possible to make a reservation for multiple cabins, and you clearly want to be able to look up the cabin assigned to a reservation.
However, you're not likely to want to look up the reservation associated with a particular cabin. (If you think you need to do so, implement it as a bidirectional relationship.)
Programming modelProgramming model Let's look at how we would mark up the Customer bean class to implement this one-to-one relationship to Address:
package com.titan.domain;
@Entitypublic class Customer implements java.io.Serializable { ... private Address address;
...@OneToOne(cascade={CascadeType.ALL}) @JoinColumn (name="ADDRESS_ID") public Address getAddress( ) { return homeAddress; } public void setAddress(Address address) { this.homeAddress = address; }
1313
Programming modelProgramming model A one-to-one relationship is specified using the
@javax.persistence.OneToOne annotation and is mapped with the @javax.persistence.JoinColumn annotation.
Let's first look at the @JoinColumn annotation:public @interface JoinColumn
{
String name( ) default "";
String referencedColumnName( ) default "";
boolean unique( ) default false;
boolean nullable( ) default true;
boolean insertable( ) default true;
boolean updatable( ) default true;
String columnDefinition( ) default "";
String table( ) default "";
}
1414
Primary-key join columnsPrimary-key join columnspackage com.titan.domain;@Entitypublic class Customer implements java.io.Serializable { ... private Address homeAddress; ...@OneToOne(cascade={CascadeType.ALL}) @PrimaryKeyJoinColumn public Address getAddress( ) { return homeAddress; } public void setAddress(Address address) {
this.homeAddress = address; }
Since we're joining on the primary keys of the Customer and Address entities and they are not composite keys, we can simply annotate the address property of Customer with the defaulted @PrimaryKeyJoinColumn annotation.
1515
One-to-one unidirectional XML mappingOne-to-one unidirectional XML mapping
We can expand our Customer entity to include a reference to a CreditCard entity, which maintains credit card information.
The Customer will maintain a reference to its CreditCard, and the CreditCard will maintain a reference back to the Customer - this makes good sense, since a CreditCard should be aware of who owns it.
Since each CreditCard has a reference back to one Customer and each Customer references one CreditCard, we have a one-to-one bidirectional relationship.
1717
Relational database schemaRelational database schema The CreditCard has a corresponding CREDIT_CARD
table, so we need to add a CREDIT_CARD foreign key to the CUSTOMER table:
CREATE TABLE CREDIT_CARD( ID INT PRIMARY KEY NOT NULL, EXP_DATE DATE, NUMBER CHAR(20), NAME CHAR(40), ORGANIZATION CHAR(20),)
CREATE TABLE CUSTOMER( ID INT PRIMARY KEY NOT NULL, LAST_NAME CHAR(20), FIRST_NAME CHAR(20), ADDRESS_ID INT, CREDIT_CARD_ID INT)
To model the relationship between the Customer and CreditCard entities, we need to declare a relationship property named customer in the CreditCard bean class:
1919
Relational database schemaRelational database schema@Entitypublic class CreditCard implements java.io.Serializable { private int id; private Date expiration; private String number; private String name; private String organization; private Customer customer; ... @OneToOne(mappedBy="creditCard") public Customer getCustomer( ) { return this.customer; } public void setCustomer(Customer customer) { this.customer = customer; }
...}
2020
Relational database schemaRelational database schema The mappedBy( ) attribute is new here. This attribute sets up the bidirectional
relationship and tells the persistence manager that the information for mapping this relationship to our tables is specified in the Customer bean class, specifically to the creditCard property of Customer.
We also need to add a relationship property to the Customer bean class for the CreditCard relationship:
One-to-Many Unidirectional RelationshipOne-to-Many Unidirectional Relationship Entity beans can also maintain relationships with
multiplicity. This means one entity bean can aggregate or contain
many other entity beans. For example, a customer may have relationships with many phones, each of which represents a phone number.
This is very different from simple one-to-one relationships - or, for that matter, from multiple one-to-one relationships with the same type of bean.
One-to-many and many-to-many relationships require the developer to work with a collection of references instead of a single reference when accessing the relationship field.
One-to-many unidirectional relationship in RDBMS using a foreign key
2626
Programming modelProgramming model You declare one-to-many relationships using the @javax.persistence.OneToMany annotation:
public @interface OneToMany
{
Class targetEntity( ) default void.class;
CascadeType[] cascade( ) default {};
FetchType fetch( ) default LAZY;
String mappedBy( ) default "";
}
The attribute definitions are pretty much the same as those for the @OneToOne annotation.
2727
Programming modelProgramming model Instead of having a different relationship field for each Phone, the Customer entity keeps all the Phones in a collection-based relationship:
@Entitypublic class Customer implements java.io.Serializable { ... private Collection<Phone> phoneNumbers = new ArrayList<Phone>( ); ... @OneToMany(cascade={CascadeType.ALL}) @JoinColumn (name="CUSTOMER_ID")
public Collection<Phone> getPhoneNumbers( ) { return phoneNumbers; } public void setPhoneNumbers(Collection<Phone> phones) { this.phoneNumbers = phones; }}
2828
Programming modelProgramming model
The Phone bean class is shown in the next listing. Notice that the Phone doesn't provide a relationship property for the Customer. It's a unidirectional relationship; the Customer entity maintains a relationship with many Phones, but the Phones do not maintain a relationship field back to the Customer. Only the Customer is aware of the relationship.
@Entitypublic class Phone implements java.io.Serializable { private int id ; private String number; private int type;
// required default constructor public Phone( ) {}
public Phone(String number, int type) { this.number = number; this.type = type; }
@Id @GeneratedValue public int getId( ) { return id; } public void setId(int id) { this.id = id; }
public String getNumber( ) { return number; } public void setNumber(String number) { this.number = number; }
public int getType( ) { return type; } public void setType(int type) { this.type = type; }}
3030
Programming modelProgramming model• To illustrate how an entity bean uses a collection-based relationship, let's look at some code that interacts with the EntityManager:
• Since the Customer entity is the owning side of the relationship, the new Phone will automatically be created in the database because the persistence manager will see that its primary key is 0, generate a new ID (GeneratorType is AUTO ), and insert it into the database.
3131
Programming modelProgramming model• If you need to remove a Phone from the relationship, you need to remove the Phone from both the collection and the database:
• Removing the Phone from the Customer's collection does not remove the Phone from the database. • You have to delete the Phone explicitly; otherwise, it will be orphaned.
3232
One-to-many unidirectional XML mappingOne-to-many unidirectional XML mapping Let's look at the XML mapping for this type of
Many-to-one unidirectional relationships result when many entity beans reference a single entity bean, but the referenced entity bean is unaware of the relationship. In the Titan Cruises business, for example, the concept of a cruise can be captured by a Cruise entity bean.
The relational database schema for the Cruise/Ship entity relationship is fairly simple;
it requires that the CRUISE table maintain a foreign key column for the SHIP table, with each row in the CRUISE table pointing to a row in the SHIP table.
The CRUISE and SHIP tables are defined in the following code snippets;
The CRUISE table maintains data on each cruise's name, ship, and other information that is not germane to this discussion. (Other tables, such as RESERVATIONS, SCHEDULES , and CREW, would have relationships with the CRUISE table through association tables.)
We'll keep it simple and focus on a definition that is useful for the examples in this book:
One-to-many and many-to-one bidirectional relationships sound like they're different, but they're not.
A one-to-many bidirectional relationship occurs when one entity bean maintains a collection-based relationship property with another entity bean, and each entity bean referenced in the collection maintains a single reference back to its aggregating bean.
For example, in the Titan Cruises system, each Cruise entity maintains a collection of references to all the passenger reservations made for that cruise, and each Reservation maintains a single reference to its Cruise.
The relationship is a one-to-many bidirectional relationship from the perspective of the Cruise and a many-to-one bidirectional relationship from the perspective of the Reservation.
4747
Relational database schemaRelational database schemaThe first table we need is the RESERVATION
table, which is defined in the following listing. Notice that the RESERVATION table contains, among other things, a column that serves as a foreign key to the CRUISE table.
While the RESERVATION table contains a foreign key to the CRUISE table, the CRUISE table doesn't maintain a foreign key back to the RESERVATION table.
The persistence manager can determine the relationship between the Cruise and Reservation entities by querying the RESERVATION table, so explicit pointers from the CRUISE table to the RESERVATION table are not required.
4949
Relational database schemaRelational database schema This illustrates the separation between the entity bean's
view of its persistence relationships and the database's actual implementation of those relationships.
One-to-many/many-to-one bidirectional relationship in RDBMS
5050
Programming modelProgramming model To model the relationship between Cruises and
Reservation entities, we first define the Reservation, which maintains a relationship field to the Cruise:
@Entity
public class Reservation implements java.io.Serializable {
Many-to-Many Bidirectional RelationshipMany-to-Many Bidirectional Relationship Many-to-many bidirectional relationships occur when
many beans maintain a collection-based relationship property with another bean, and each bean referenced in the collection maintains a collection-based relationship property back to the aggregating beans.
For example, in Titan Cruises, every Reservation entity may reference many Customers (a family can make a single reservation), and each Customer can have many reservations (a person may make more than one reservation).
In this many-to-many bidirectional relationship, the Customer keeps track of all of its reservations, and each reservation may be for many customers.
5656
Relational database schemaRelational database schema The RESERVATION and CUSTOMER tables have
already been established. To establish a many-to-many bidirectional
relationship, we create the RESERVATION_CUSTOMER table.
This table maintains two foreign key columns: one for the RESERVATION table and another for the CUSTOMER table:
CREATE TABLE RESERVATION_CUSTOMER
(
RESERVATION_ID INT,
CUSTOMER_ID INT
)
5757
Relational database schemaRelational database schemaThe relationship between the CUSTOMER,
RESERVATION, and RESERVATION_CUSTOMER tables is illustrated in the figure below:
public Set<Customer> getCustomers( ) { return customers; }
public void setCustomers(Set customers);
...
}
6060
Relational database schemaRelational database schema We have also modified the Customer to allow it to
maintain a collection-based relationship with all of its Reservations.
The Customer bean class now includes a reservations relationship property:@Entitypublic class Customer implements java.io.Serializable { ... private Collection<Reservation> reservations = new
As with one-to-many bidirectional relationships, the mappedBy( ) attribute identifies the property on the Reservation bean class that defines the relationship.
This also identifies the Customer entity as the inverse side of the relationship.
6262
Many-to-many bidirectional XML mappingMany-to-many bidirectional XML mapping
Let's look at the XML mapping for this type of relationship:<entity-mappings>
Many-to-Many Unidirectional RelationshipMany-to-Many Unidirectional Relationship Many-to-many unidirectional relationships occur when many
beans maintain a collection-based relationship with another bean, but the bean referenced in the Collection does not maintain a collection-based relationship back to the aggregating beans.
In Titan's reservation system, every Reservation is assigned a Cabin on the Ship. This allows a customer to reserve a specific cabin (e.g., a deluxe suite or a cabin with sentimental significance) on the ship.
In this case, each reservation may be for more than one cabin, since each reservation can be for more than one customer.
For example, a family might make a reservation for five people for two adjacent cabins (one for the kids and the other for the parents).
6565
Relational database schemaRelational database schema Our first order of business is to declare a CABIN table:
CREATE TABLE CABIN
(
ID INT PRIMARY KEY NOT NULL,
SHIP_ID INT,
NAME CHAR(10),
DECK_LEVEL INT,
BED_COUNT INT
)
The CABIN table maintains a foreign key to the SHIP table.
While this relationship is important, we don't discuss it because we covered the one-to-many bidirectional relationship earlier.
6666
Relational database schemaRelational database schema To accommodate the many-to-many unidirectional
relationship between the RESERVATION and CABIN tables, we need a CABIN_RESERVATION table:
The java.util.List interface can express collection-based relationships.
You do not need any special metadata if you want to use a List rather than a Set or Collection type. (In this case, the List actually gives you a bag semantic, an unordered collection that allows duplicates).
A List type can give you the additional ability to order the returned relationship based on a specific set of criteria.
Map-Based RelationshipMap-Based Relationship The java.util.Map interface can be used to express
collection-based relationships. In this case, the persistence provider creates a map with the key being a specific property of the related entity and the value being the entity itself.
If you use a java.util.Map, you must use the @javax.persistence.MapKey annotation:
package javax.persistence;
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface MapKey
{
String name( ) default "";
}
7878
Map XML mappingMap XML mapping
Here's what the XML mapping would be for this example:
CascadingCascading There is one annotation attribute that we have ignored so far: the cascade( ) attribute of the @OneToOne, @OneToMany, @ManyToOne , and @ManyToMany relationship annotations. With the Java Persistence specification, cascading can be applied to a variety of entity manager operations, including persist( ), merge( ), remove( ), and refresh( ). This feature is enabled by setting the javax.persistence.CascadeType of the
relationship annotation's cascade( ) attribute. The CascadeType is defined as a Java enumeration: public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH }
Let's look again at the one-to-one unidirectional relationship between the Customer and Address entities we discussed earlier in this chapter. As you can see, it has a CascadeType of both REMOVE and PERSIST: package com.titan.domain;
@Entity public class Customer implements java.io.Serializable { ... private Address homeAddress;
Whenever you persist( ) a Customer and the Address entity associated with the Customer is also new, the Address is also persisted. If you remove( ) the Customer, the associated Address entity is also removed from the database. Let's look at this same example expressed in an XML mapping:
CascadingCascading There is one annotation attribute that we have
ignored so far: the cascade( ) attribute of the @OneToOne, @OneToMany, @ManyToOne , and @ManyToMany relationship annotations.
With the Java Persistence specification, cascading can be applied to a variety of entity manager operations, including persist( ), merge( ), remove( ), and refresh( ).
This feature is enabled by setting the javax.persistence.CascadeType of the relationship annotation's cascade( ) attribute.
The CascadeType is defined as a Java enumeration:
8181
CascadingCascading
public enum CascadeType
{
ALL, PERSIST,
MERGE, REMOVE,
REFRESH
}
Let's look again at the one-to-one unidirectional relationship between the Customer and Address entities we discussed earlier in this chapter.
As you can see, it has a CascadeType of both REMOVE and PERSIST:
8282
CascadingCascadingpackage com.titan.domain;
@Entity
public class Customer implements java.io.Serializable {
CascadingCascading Whenever you persist( ) a Customer and the Address entity
associated with the Customer is also new, the Address is also persisted.
If you remove( ) the Customer, the associated Address entity is also removed from the database. Let's look at this same example expressed in an XML mapping:<entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <attributes> <id name="id"> <generated-value/> </id> <one-to-one name="address" targetEntity="com.titan.domain.Address" fetch="LAZY" optional="true"> <cascade-persist/> <cascade-remove/> <primary-key-join-column/> </one-to-one> </attributes> </entity></entity-mappings>
8484
PERSISTPERSIST
PERSIST has to deal with the creation of entities within the database.
If we had a CascadeType of PERSIST on the Customer side of our one-to-one relationship, you would not have to persist your created Address as well.
It would be created for you. The persistence provider will also execute the appropriate SQL INSERT statements in the appropriate order for you:Customer cust = new Customer( );Address address = new Address( );cust.setAddress(address);entityManager.persist(cust);
8585
MERGEMERGE MERGE deals with entity synchronization, meaning
inserts and, more importantly, updates. If you have a cascade policy of MERGE, then you do not
have to call EntityManager.merge( ) for the contained related entity:
cust.setName("William");
cust.getAddress( ).setCity("Boston");
entityManager.merge(cust);
In this example, when the cust variable is merged by the entity manager, the entity manager will cascade the merge to the contained address property and the city will also be updated in the database.
8686
REMOVEREMOVE
REMOVE is straightforward. In our Customer example, if you delete a Customer entity, its address will be deleted as well.
This is exactly the same kind of functionality that is in EJB 2.1 CMP.
REFRESHREFRESH REFRESH is similar to MERGE. Unlike merge, though,
this only pertains to when EntityManager.refresh( ) is called.
Refreshing doesn't update the database with changes in the object instance. Instead, it refreshes the object instance's state from the database. Again, the contained related entities would also be refreshed.
Customer cust ...;entityManager.refresh(cust); // address would be refreshed too
So, if changes to the Customer's address were committed by a different transaction, the address property of the cust variable would be updated with these changes.
8888
ALLALL
ALL is a combination of all of the previous policies and is used for the purposes of simplicity.
8989
When to Use CascadingWhen to Use Cascading You don't always want to use cascading for every
relationship you have. For instance, you would not want to remove the
related Cruise or Customer when removing a Reservation entity from the database because these entities have a life span that is usually longer than the Reservation.
You might not want to cascade merges because you may have fetched stale data from the database or simply not filled the relationship in one particular business operation.
9090
When to Use CascadingWhen to Use Cascading
For performance reasons, you may also not want to refresh all the relationships an entity has because this would cause more round trips to the database.
Be aware how your entities will be used before deciding on the cascade type. If you are unsure of their use, then you should turn off cascading entirely.
Remember, cascading is simply a convenient tool for reducing the EntityManager API calls.