Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Mapping Persistent Objects Entities represent data in the database, so changes to an entity bean result in changes to the database. That's ultimately.

Similar presentations


Presentation on theme: "1 Mapping Persistent Objects Entities represent data in the database, so changes to an entity bean result in changes to the database. That's ultimately."— Presentation transcript:

1 1 Mapping Persistent Objects Entities represent data in the database, so changes to an entity bean result in changes to the database. That's ultimately the purpose of an entity bean: to provide programmers with a simpler mechanism for accessing and changing data. It is much easier to change a customer's name by calling Customer.setName( ) than by executing an SQL command against the database.

2 2 Mapping Persistent Objects When a new entity is created and persisted into the entity manager service, a new record must be inserted into the database and a bean instance must be associated with that data. As the entity is used and its state changes, these changes must be synchronized with the data in the database: entries must be inserted, updated, and removed. The process of coordinating the data represented by a bean instance with the database is called persistence.

3 3 The Customer Bean The Customer bean is a simple entity bean that models the concept of a cruise customer or passenger, but its design and use are applicable across many commercial domains.

4 4 The Bean Class The Customer bean class is a plain Java object that you map to your relational database. It has fields that hold state and, optionally, it has getter and setter methods to access this state. It must have, at minimum, a no-argument constructor:

5 5 The Bean Class package com.titan.domain; import javax.persistence.*; @Entity public class Customer implements java.io.Serializable { private long id; private long id; private String firstName; private String firstName; private String lastName; private String lastName; @Id @Id public long getId( ) { return id; } public long getId( ) { return id; } public void setId(long id) { this.id = id; } public void setId(long id) { this.id = id; } public String getFirstName( ) { return firstName; } public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName( ) { return lastName; } public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setLastName(String lastName) { this.lastName = lastName; }

6 6 The Bean Class Here is the table definition the persistence provider is assuming you are mapping to: create table Customer( id long primary key not null, firstName VARCHAR(255), lastName VARCHAR(255) ); The @javax.persistence.Entity annotation tells the persistence provider that your class can be persisted: package javax.persistence; @Target(TYPE) @Retention(RUNTIME) public @interface Entity { String name( ) default ""; }

7 7 The Bean Class The @Entity annotation has one name( ) attribute. This name is used to reference the entity within an EJB QL expression. If you do not provide a value for this attribute, the name defaults to the unqualified name of the bean class. How you apply the @javax.persistence.Id annotation determines whether you will use the Java bean style for declaring your persistent properties or whether you will use Java fields.

8 8 The Bean Class If you place the @Id annotation on a getter method, as done in this example, then you must apply any other mapping annotations on getter and setter methods in the class. The provider will also assume that any other getter and setter methods in your class represent persistent properties and will automatically map them based on their base name and type.

9 9 The Bean Class @Entity public class Customer implements java.io.Serializable { @Id private long id; private String firstName; private String lastName; public long getId( ) { return id; } public void setId(long id) { this.id = id; } public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }

10 10 The Bean Class Here, we have placed the @Id annotation on a member field of the class. The persistence provider will also assume that any other member fields of the class are also persistent properties and will automatically map them based on their base name and type. Any mapping annotations must be placed on member fields in this example, not on getter or setter methods. Here, we are really defining the access type - that is, whether our relational mappings are defined on the fields or the methods of a class.

11 11 XML Mapping File If you do not want to use annotations to identify and map your entity beans, you can alternatively use an XML mapping file to declare this metadata. By default, the persistence provider will look in the META-INF directory for a file named orm.xml, or you can declare the mapping file in the element in the persistence.xml deployment descriptor. Here's how the Customer entity mapping would look in XML:

12 12 XML Mapping File The element defines the entity class and access type: PROPERTY or FIELD. Like annotated classes, the persistence provider will assume that any other property in your class is a persistent property, and you do not have to explicitly define them.

13 13 Basic Relational Mapping A developer can take two directions when implementing entity beans. Some applications start from a Java object model and derive a database schema from this model. Other applications have an existing database schema from which they have to derive a Java object model. If you are creating a database schema from a Java object model, most persistence vendors have tools that can autogenerate database schemas based on the annotations or XML metadata you provide in your code.

14 14 Basic Relational Mapping If you have an existing database schema, many vendors have tools that can generate Java entity code directly from it. Sometimes, though, this generated code is not very object-oriented and doesn't map to your database very well. Luckily, the Java Persistence specification provides the necessary mapping capabilities to facilitate this problem.

15 15 Elementary Schema Mappings Here's the table definition in SQL: create table CUSTOMER_TABLE ( CUST_ID integer primary key not null, FIRST_NAME varchar(20) not null lastName varchar(255) not null, ); We want to change the table name and the column names of the id and firstName properties. We want to change the table name and the column names of the id and firstName properties. We also want firstName to have a not-null constraint and want to set the VARCHAR length to 20. We also want firstName to have a not-null constraint and want to set the VARCHAR length to 20.

16 16 Elementary Schema Mappings Let's modify our original Customer entity class and add the mapping annotations: package com.titan.domain; import javax.persistence.*; @Entity @Table (name="CUSTOMER_TABLE") public class Customer implements java.io.Serializable { private long id; private String firstName; private String lastName;

17 17 Elementary Schema Mappings @Id @Column(name="CUST_ID", nullable=false, columnDefinition="integer") public long getId( ) { return id; } public void setId(long id) { this.id = id; } @Column(name="FIRST_NAME", length=20, nullable=false) public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }

18 18 @Table Let's look at the full definition of this annotation: Let's look at the full definition of this annotation: package javax.persistence; @Target({TYPE}) @Retention(RUNTIME) public @interface Table { String name( ) default ""; String name( ) default ""; String catalog( ) default ""; String catalog( ) default ""; String schema( ) default ""; String schema( ) default ""; UniqueConstraint uniqueConstraints( ) default {}; UniqueConstraint uniqueConstraints( ) default {};}

19 19 @Table The catalog( ) and schema( ) attributes are self-explanatory, as they identify the relational catalog and schema the table belongs to: public @interface UniqueConstraint { String[] columnNames( ); }

20 20 @Column @javax.persistence.Column annotation describes how a particular field or property is mapped to a specific column in a table: public @interface Column { String name( ) default ""; boolean unique( ) default false; boolean nullable( ) default true; boolean insertable( ) default true; boolean updatable( ) default true; String columnDefinition( ) default ""; String table( ) default ""; int length( ) default 255; int precision( ) default 0; int scale( ) default 0; }

21 21 @Column The @Column annotation has the XML equivalent in the element. This element is a subelement of the attribute mapping types,,,, and that are described later in this chapter. <column name="" <column name="" unique="true" unique="true" nullable="true" nullable="true" insertable="true" insertable="true" updatable="true" updatable="true" column-definition="" column-definition="" table="" table="" length="" length="" precision="" precision="" scale="" scale="" /> /></basic>

22 22 Primary Keys Primary keys can map to one or more properties and must map to one of the following types: any Java primitive type (including wrappers), java.lang.String, or a primary-key class composed of primitives and/or strings. Let's first focus on simple one-property primary keys.

23 23 @Id The @javax.persistence.Id annotation identifies one or more properties that make up the primary key for your table: package javax.persistence; @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Id {} You can generate the primary key for your entity beans manually or have the persistence provider do it for you.

24 24 @Id When you want provider-generated keys, you have to use the @javax.persistence.GeneratedValue annotation: package javax.persistence; @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface GeneratedValue { GenerationType strategy( ) default AUTO; String generator( ) default ""; } public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO }

25 25 @Id Persistence providers are required to provide key generation for primitive primary keys. You can define the type of primary generator you would like to have using the strategy( ) attribute. The GeneratorType.AUTO strategy is the most commonly used configuration. The AUTO strategy tells the persistence provider that you are allowing it to generate the key for you. The IDENTITY strategy uses a special column type, available in many database implementations, for creating primary keys.

26 26 Table Generators The TABLE strategy designates a user-defined relational table from which the numeric keys will be generated. A relational table with the following logical structure is used: create table GENERATOR_TABLE ( PRIMARY_KEY_COLUMN VARCHAR not null, VALUE_COLUMN long not null ); This annotation can be applied to a class or to the method or field of the primary key:

27 27 Table Generators package javax.persistence; @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) public @interface TableGenerator { String name( ); String table( ) default ""; String catalog( ) default ""; String schema( ) default ""; String pkColumnName( ) default ""; String valueColumnName( ) default ""; String pkColumnValue( ) default ""; int allocationSize( ) default 50; UniqueConstraint[] uniqueConstraints( ) default {}; }

28 28 Table Generators Let's look at how you would actually use this generator on the Customer entity: package com.titan.domain import javax.persistence.*; @Entity public class Customer implements java.io.Serializable { private long id; private String firstName; private String lastName; @TableGenerator(name="CUST_GENERATOR" table="GENERATOR_TABLE" pkColumnName="PRIMARY_KEY_COLUMN" valueColumnName="VALUE_COLUMN" pkColumnValue="CUST_ID" allocationSize=10)

29 29 Table Generators @Id @GeneratedValue (strategy=GenerationType.TABLE, generator="CUST_GENERATOR") public long getId( ) { return id; } public void setId(long id) { this.id = id; } public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName;

30 30 Table Generators Now if you allocate and persist( ) a Customer entity, the id property will be autogenerated when the persist() operation is called. Let's look at how this would be defined within XML: <table-generator name="CUST_GENERATOR" table="GENERATOR_TABLE" pk-column-name="PRIMARY_KEY_COLUMN" value-column-name="VALUE_COLUMN" pk-column-value="CUST_ID" allocation-size="10"/>

31 31 Sequence Generators Some RDBMs, specifically Oracle, have an efficient, built-in structure to generate IDs sequentially. This is the SEQUENCE generator strategy. This generator type is declared via the @javax.persistence.SequenceGenerator : package javax.persistence; @Target({METHOD, TYPE, FIELD}) @Retention(RUNTIME) public @interface SequenceGenerator { String name( ); String sequenceName( ) default ""; int initialValue( ) default 1; int allocationSize( ) default 50; }

32 32 Sequence Generators Let's again look at applying the SEQUENCE strategy on our Customer entity bean: package com.titan.domain import javax.persistence.*; @Entity @Table(name="CUSTOMER_TABLE") @SequenceGenerator(name="CUSTOMER_SEQUENCE", sequenceName="CUST_SEQ") public class Customer implements java.io.Serializable { private long id; private String firstName; private String lastName;

33 33 Sequence Generators @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CUSTOMER_SEQUENCE") public long getId( ) { return id; } public void setId(long id) { this.id = id; } public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } } This example is a little different from our TABLE strategy example in that the generator is declared on the bean's class instead of directly on the property.

34 34 Sequence Generators TABLE and SEQUENCE generators can be defined in either place. As with the TABLE generation type, the primary key is autogenerated when the EntityManager.persist( ) operation is performed.

35 35 Sequence Generators Let's look at the XML equivalent for this mapping: <sequence-generator name="CUSTOMER_SEQUENCE" sequence-name="CUST_SEQ" initial-value="0" allocation-size="50"/>

36 36 Primary-Key Classes and Composite Keys Sometimes relational mappings require a primary key to be composed of multiple persistent properties. For instance, let's say that our relational model specified that our Customer entity should be identified by both its last name and its Social Security number instead of an autogenerated numeric key. These are called composite keys. The Java Persistence specification provides multiple ways to map this type of model. One is through the @javax.persistence.IdClass annotation; The other is through the @javax.persistence.EmbeddedId annotation.

37 37 @IdClass @IdClass is a class-level annotation and specifies what primary-key class you should use when interacting with the entity manager. @Target(TYPE) @Retention(RUNTIME) public @interface IdClass { Class value( ); } First, let's define our primary-key class:

38 38 @IdClass package com.titan.domain; public class CustomerPK implements java.io.Serializable { private String lastName; private long ssn; public CustomerPK( ) {} public CustomerPK(String lastName, long ssn) { this.lastName = lastName; this.ssn = ssn; } public String getLastName( ) { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; }

39 39 @IdClass public long getSsn( ) { return ssn; } public void setSsn(long ssn) { this.ssn = ssn; } public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof CustomerPK)) return false; CustomerPK pk = (CustomerPK)obj; if (!lastName.equals(pk.lastName)) return false; if (ssn != pk.ssn) return false; return true; } public int hashCode( ) { return lastName.hashCode( ) + (int)ssn; }

40 40 @IdClass The primary-key class must meet these requirements: It must be serializable. It must have a public no-arg constructor. It must implement the equals( ) and hashCode( ) methods. Our Customer bean must have the same exact properties as the CustomerPK class, and these properties are annotated with multiple @Id annotations:

41 41 @IdClass package com.titan.domain; import javax.persistence.*; @Entity @IdClass(CustomerPK.class) public class Customer implements java.io.Serializable { private String firstName; private String lastName; private long ssn; public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } @Id public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; }

42 42 @IdClass @Id public long getSsn( ) { return ssn; } public void setSsn(long ssn) { this.ssn = ssn; } } Let's now look at the XML mapping equivalent to @IdClass: com.titan.domain.CustomerPK

43 43 @EmbeddedId A different way to define primary-key classes and composite keys is to embed the primary-key class directly in your bean class. The @javax.persistence.EmbeddedId annotation is used for this purpose in conjunction with the @javax.persistence.Embeddable annotation: package javax.persistence; public @interface EmbeddedId { } public @interface AttributeOverrides { AttributeOverride[] value( ); }

44 44 @EmbeddedId public @interface AttributeOverride { String name( ); Column[] column( ) default {}; } public @interface Embeddable { } There are two ways to map the properties of your primary-key class to columns in your table. One is to specify the @Column mappings within the primary-key class source code; The other is to use @AttributeOverrides.

45 45 Property Mappings Java Persistence has mappings for JDBC Blobs and Clob s, serializable objects, and embeddable objects, as well as optimistic concurrency with version properties. We will discuss all of these.

46 46 @Transient You may have properties that you don't want to be persistent, and, therefore, the default behavior is inappropriate. This is where the @javax.persistence.Transient annotation comes in: @Entity public class Customer implements java.io.Serializable { private String firstName; private CustomerPK pk; public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; }

47 47 @Transient @Transient public String getLastName( ) { return pk.getLastName( ); } @Transient public long getSsn( ) { return pk.getSsn( ); } @EmbeddedId public PK getPk( ) { return pk; } public void setPk(CustomerPK pk) { this.pk = pk; } }

48 48 @Transient Here is what the XML equivalent looks like:

49 49 @Basic and FetchType The @Basic annotation is the simplest form of mapping for a persistent property. This is the default mapping type for properties which are primitives, primitive wrapper types, java.lang.String, byte[ ], Byte[ ], char[ ], Character[ ], java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, and java.sql.Timestamp. You do not need to tell your persistence manager explicitly that you're mapping a basic property because it can usually figure out how to map it to JDBC using the property's type.

50 50 @Basic and FetchType public @interface Basic { FetchType fetch( ) default EAGER; boolean optional( ) default true; } public enum FetchType { LAZY, EAGER } Let's take our Customer entity and show how to use the @Basic annotation:

51 51 @Basic and FetchType package com.titan.domain import javax.persistence.*; @Entity public class Customer implements java.io.Serializable { private long id; private String firstName; private String lastName; @Id @GeneratedValue public long getId( ) { return id; } public void setId(long id) { this.id = id; } @Basic(fetch=FetchType.LAZY, optional=false) public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; }

52 52 @Basic and FetchType The @Basic annotation also has an XML equivalent:

53 53 @Lob Sometimes your persistent properties require a lot of memory. The @javax.persistence.Lob annotation is used to map these large object types. Java Persistence allows you to map some basic types to a @Lob and have the persistence manager handle them internally as either a Blob or a Clob, depending on the type of the property:

54 54 @Lob package javax.persistence; public @interface Lob { } Properties annotated with a @Lob are persisted in a: Blob if the Java type is byte[ ], Byte[ ], or java.io.Serializable Clob if the Java type is char[ ], Character[ ], or java.lang.String

55 55 @Enumerated The @Enumerated annotation maps Java enum types to the database. It is used in conjunction with the @Basic annotation and lets you specify additional fetch semantics: package javax.persistence; public enum EnumType { ORDINAL, STRING } public @interface Enumerated { EnumType value( ) default ORDINAL; }

56 56 @Enumerated A Java enum property can be mapped either to the string representation or to the numeric ordinal number of the enum value. For example, let's say we want a Customer entity property that designates the kind of customer that is purchasing a reservation. This could be represented in a Java enum called CustomerType with the enum values UNREGISTERED, REGISTERED, or BIG_SPENDAH. We would do it as follows:

57 57 @Enumerated package com.titan.domain; import javax.persistence.*; public enum CustomerType { UNREGISTERED, REGISTERED, BIG_SPENDAH } @Entity public class Customer implements java.io.Serializable { private long id; private String firstName; private String lastName; private CustomerType customerType; @Id @GeneratedValue public long getId( ) { return id; } public void setId(long id) { this.id = id;

58 58 @Enumerated public String getFirstName( ) { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName( ) { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Enumerated (EnumType.STRING) public CustomerType getCustomerType( ) { return customerType; } public void setCustomerType(CustomerType type) { customerType = type; } }

59 59 @Enumerated Here's the XML equivalent: STRING

60 60 Multitable Mappings with @SecondaryTable Sometimes you have to deal with one logical entity that is stored in two different tables. You want one entity bean class to represent your object, but it is mapped into two different tables because you're working with a legacy database model. Java Persistence allows you to map an entity bean class to one or more tables using the @javax.persistence.SecondaryTable annotation. For example, let's say our Customer bean has properties that define the address of the Customer, but the address data is stored in a separate table.

61 61 Multitable Mappings with @SecondaryTable Here's what the tables would look like: create table CUSTOMER_TABLE ( CUST_ID integer Primary Key Not Null, FIRST_NAME varchar(20) not null, LAST_NAME varchar(50) not null ); create table ADDRESS_TABLE ( ADDRESS_ID integer primary key not null, STREET varchar(255) not null, CITY varchar(255) not null, STATE varchar(255) not null );

62 62 Multitable Mappings with @SecondaryTable To use the @SecondaryTable annotation, the primary key columns of the ADDRESS_TABLE must be joinable with one or more columns in the CUSTOMER_TABLE: public @interface SecondaryTable { String name( ); String catalog( ) default ""; String schema( ) default ""; PrimaryKeyJoinColumn[] pkJoinColumns( ) default {}; UniqueConstraint[] uniqueConstraints( ) default {}; } public @interface PrimaryKeyJoinColumn { String name( ) default ""; String referencedColumnName( ) default ""; String columnDefinition( ) default ""; }

63 63 Multitable Mappings with @SecondaryTable The referencedColumnName( ) attribute represents the column name in the CUSTOMER_TABLE that is used to join with the ADDRESS_TABLE. package com.titan.domain; import javax.persistence.*; import com.acme.imaging.JPEG; @Entity @Table(name="CUSTOMER_TABLE") @SecondaryTable(name="ADDRESS_TABLE", pkJoinColumns={ @PrimaryKeyJoinColumn(name="ADDRESS_ID")}) public class Customer implements java.io.Serializable {...

64 64 Multitable Mappings with @SecondaryTable The next step is to map the street, city, and state properties to columns in the ADDRESS_TABLE. If you remember the full @Column annotation, one of the attributes we did not go over fully is the table( ) attribute. You use this to map the address properties to your secondary table: package com.titan.domain; import javax.persistence.*; import com.acme.imaging.JPEG; @Entity @Table(name="CUSTOMER_TABLE") @SecondaryTable(name="ADDRESS_TABLE", pkJoinColumns={ @PrimaryKeyJoinColumn(name="ADDRESS_ID")})

65 65 Multitable Mappings with @SecondaryTable public class Customer implements java.io.Serializable { private long id; private String firstName; private String lastName; private String street; private String city; private String state;... @Column(name="STREET", table="ADDRESS_TABLE") public String getStreet( ) { return street; } public void setStreet(String street) { this.street = street; } @Column(name="CITY", table="ADDRESS_TABLE") public String getCity( ) { return city; } public void setCity(String city) { this.city = city; } @Column(name="STATE", table="ADDRESS_TABLE") public String getState( ) { return state; } public void setState(String state) { this.state = state; }...

66 66 Multitable Mappings with @SecondaryTable What do you do if you have more than one secondary table? For example, let's say that you want to embed credit card properties, but this information was also stored in another table. In that instance, you would use the @SecondaryTables annotation.


Download ppt "1 Mapping Persistent Objects Entities represent data in the database, so changes to an entity bean result in changes to the database. That's ultimately."

Similar presentations


Ads by Google