Understanding JPA,4

4780 ワード

Page 4 of 6
A composite primary key
Now, how do you find a record in the database with a primary key if the entity has a composite primary key? You'll see how that works in a moment. Assume that the CUSTOMER table doesn't have a CUST_ID field, but that FIRST_NAME and LAST_NAME together make up the primary key. To make this work, you need to create a separate class, generally called an identity class, with attributes the same as the IDs; then you reference the identity class in the entity class. This is shown in Listing 7.
Listing 7. An identity class public class CustomerId {
public String firstName;
public String lastName;
// override equal() method
//override hascode() method
..................
}

The identity class can be a separate class or an inner class. If the class is an inner class, it must be static and should be referenced in the entity class, as in Listing 8. The code for finding records with a composite primary key is exactly the same as that for finding records with a single primary key.
Listing 8. Using an identity class @Entity
@IdClass(Customer.CustomerId.class)
public class Customer implements Serializable{
@Id
@Column(name = "FIRST_NAME", nullable = false, length = 50)
private String firstName;

@Id
@Column(name = "LAST_NAME", length = 50)
private String lastName;

private String street;

@Column(name = "APPT",nullable = false)
private String appt;

................
}
The callbacks
JPA provides callback methods for performing actions at different stages of persistence operations. Imagine that you want to update a customer record, but, before you update, you want to remove the hyphen from the zip code if one is present. Or say that you want to populate some transient fields after a successful fetch. JPA provides listeners for these kinds of activities before and after each fetch, insert, or update operation. The callback methods can be annotated as any of the following:
  • @PostLoad
  • @PrePersist
  • @PostPersist
  • @PreUpdate
  • @PostUpdate
  • @PreRemove
  • @PostRemove

  • You can write the callback methods in the entity class itself, or you can write them in a separate class and reference them in the entity class with @EntityListeners , as shown in Listing 9.
    Listing 9. implementing callback @EntityListeners({CustListner.class})
    @Entity(name = "CUSTOMER") //Name of the entity
    public class Customer implements Serializable{
    ...
    ...
    }
    public class CustListner {
    @PreUpdate
    public void preUpdate(Customer cust) {
    System.out.println("In pre update");
    }
    @PostUpdate
    public void postUpdate(Customer cust) {
    System.out.println("In post update");
    }
    }
    Embedded objects
    As you've seen so far, the Customer entity has the address information inline in the entity itself. What if you want to apply class normalization concepts and come up with a separate Address class and refer to that in the Customer entity? After all, an address object could be used with Customer , Employee , Order , or User entities.
    All you need is an embedded object. You move the address information into a separate class and mark that class as being embeddable, as shown in Listing 10. Refer to this newly created class from the Customer entity with @Embedded annotations.
    Listing 10. An embeddable class @Embeddable
    public class Address implements Serializable{

    private String street;

    @Column(name = "APPT",nullable = false)
    private String appt;

    private String city;
    ..
    ..
    }
    Embedded classes are mapped together with their owning entity as part of the state of that entity. However, they cannot be queried separately. Listing 11 illustrates a sample entity that uses an embedded object.
    Listing 11. A sample entity using an embedded object @Entity
    public class Customer {
    ...............
    @Column(name = "FIRST_NAME", nullable = false,length = 50)
    private String firstName;

    @Embedded
    private Address address;
    ..............
    }