1 / 66

Mapping Persistent Objects

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.

violet-best
Download Presentation

Mapping Persistent Objects

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  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. 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. 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. 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. The Bean Class 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 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; }

  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. 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. 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. 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. 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. 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 <mapping-file> element in the persistence.xml deployment descriptor. • Here's how the Customer entity mapping would look in XML:

  12. XML Mapping File <entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <attributes> <id name="id"/> </attributes> </entity> </entity-mappings> • The <entity> 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. 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. 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. 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 also want firstName to have a not-null constraint and want to set the VARCHAR length to 20.

  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. 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. @Table • Let's look at the full definition of this annotation: package javax.persistence; @Target({TYPE}) @Retention(RUNTIME) public @interface Table { String name( ) default ""; String catalog( ) default ""; String schema( ) default ""; UniqueConstraint uniqueConstraints( ) default {}; }

  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. @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. @Column • The @Column annotation has the XML equivalent in the <column> element. This element is a subelement of the attribute mapping types <id>, <basic>, <temporal>, <lob>, and <enumerated> that are described later in this chapter. <basic name="lastName"> <column name="" unique="true" nullable="true" insertable="true" updatable="true" column-definition="" table="" length="" precision="" scale="" /> </basic>

  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. @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. @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. @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. 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. 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. 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. 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. 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: <entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <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"/> <attributes> <id name="id"> <generated-value strategy="TABLE" generator="CUST_GENERATOR"/> </id> </attributes> </entity> </entity-mappings>

  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. 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. 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. 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. Sequence Generators • Let's look at the XML equivalent for this mapping: <entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <sequence-generator name="CUSTOMER_SEQUENCE" sequence-name="CUST_SEQ" initial-value="0" allocation-size="50"/> <attributes> <id name="id"> <generated-value strategy="SEQUENCE" generator="CUSTOMER_SEQUENCE"/> </id> </attributes> </entity> </entity-mappings>

  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. @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. @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. @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. @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. @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. @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: <entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <id-class>com.titan.domain.CustomerPK</id-class> <attributes> <id name="lastName"/> <id name="ssn"/> </attributes> </entity> </entity-mappings>

  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. @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. 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. @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. @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. @Transient • Here is what the XML equivalent looks like: <entity-mappings> <embeddable class="com.titan.domain.CustomerPK" access-type="PROPERTY"> <embeddable-attribute name="lastName"> <column name="CUSTOMER_LAST_NAME"/> </embeddable-attribute> <embeddable-attribute name="ssn"> <column name="CUSTOMER_SSN"/> </embeddable-attribute> </embeddable> <entity class="com.titan.domain.Customer" access="PROPERTY"> <attributes> <embedded-id name="pk"/> <transient name="lastName"/> <transient name="ssn"/> </attributes> </entity> </entity-mappings>

  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. @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:

More Related