Hibernate inheritance mapping example

how to create hibernate mapping file in myeclipse and inheritance mapping in hibernate
GregDeamons Profile Pic
GregDeamons,New Zealand,Professional
Published Date:03-08-2017
Your Website URL(Optional)
Part 2 Mapping concepts and strategies T his part is all about actual object/relational mapping, from classes and properties to tables and columns. Chapter 4 starts with regular class and property mappings, and explains how you can map fine-grained Java domain models. Next, in chapter 5, you’ll see how to map more complex class inher- itance hierarchies and how to extend Hibernate's functionality with the pow- erful custom mapping type system. In chapters 6 and 7, we show you how to map Java collections and associations between classes, with many sophisti- cated examples. Finally, you’ll find chapter 8 most interesting if you need to introduce Hibernate in an existing applications, or if you have to work with legacy database schemas and hand-written SQL. We also talk about custom- ized SQL DDL for schema generation in this chapter. After reading this part of the book, you’ll be ready to create even the most complex mappings quickly and with the right strategy. You’ll under- stand how the problem of inheritance mapping can be solved, and how col- lections and associations can be mapped. You’ll also be able to tune and customize Hibernate for integration with any existing database schema or application. 158 CHAPTER 4 Mapping persistent classes This chapter presents the fundamental mapping options, explaining how classes and properties are mapped to tables and columns. We show and discuss how you can handle database identity and primary keys, and how various other metadata settings can be used to customize how Hibernate loads and stores objects. All XML format, and with JPA mapping examples are done in Hibernate’s native annotations and XML descriptors, side by side. We also look closely at the map- ping of fine-grained domain models, and at how properties and embedded com- ponents are mapped. First, though, we define the essential distinction between entities and value types, and explain how you should approach the object/relational mapping of your domain model. 4.1 Understanding entities and value types Entities are persistent types that represent first-class business objects (the term object is used here in its natural sense). In other words, some of the classes and types you have to deal with in an application are more important, which naturally makes others less important. You probably agree that in CaveatEmptor, Item is a more important class than String. User is probably more important than Address. What makes something important? Let’s look at the issue from a differ- ent perspective. 4.1.1 Fine-grained domain models A major objective of Hibernate is support for fine-grained domain models, which we isolated as the most important requirement for a rich domain model. It’s one reason why we work with POJOs. In crude terms, fine-grained means more classes than tables. For example, a user may have both a billing address and a home address. In the database, you may have a single USERS table with the columns BILLING_STREET, BILLING_CITY, and BILLING_ZIPCODE, along with HOME_STREET, HOME_CITY, and HOME_ZIPCODE. (Remember the problem of SQL types we discussed in chapter 1?) In the domain model, you could use the same approach, representing the two addresses as six string-valued properties of the User class. But it’s much better to model this using an Address class, where User has the billingAddress and homeAddress properties, thus using three classes for one table. This domain model achieves improved cohesion and greater code reuse, and it’s more understandable than SQL systems with inflexible type systems. InUnderstanding entities and value types 159 the past, many ORM solutions didn’t provide especially good support for this kind of mapping. Hibernate emphasizes the usefulness of fine-grained classes for implementing type safety and behavior. For example, many people model an email address as a User. A more sophisticated approach is to define an string-valued property of EmailAddress class, which adds higher-level semantics and behavior—it may pro- vide a sendEmail() method. This granularity problem leads us to a distinction of central importance in ORM. In Java, all classes are of equal standing—all objects have their own identity and lifecycle. Let’s walk through an example. 4.1.2 Defining the concept Two people live in the same apartment, and they both register user accounts in CaveatEmptor. Naturally, each account is represented by one instance of User, so you have two entity instances. In the CaveatEmptor model, the User class has a homeAddress association with the Address class. Do both User instances have a runtime reference to the same Address instance or does each User instance have a reference to its own Address? If Address is supposed to support shared runtime references, it’s an entity type. If not, it’s likely a value type and hence is dependent on a single reference by an owning entity instance, which also provides identity. We advocate a design with more classes than tables: One row represents multi- ple instances. Because database identity is implemented by primary key value, some persistent objects won’t have their own identity. In effect, the persistence mechanism implements pass-by-value semantics for some classes One of the objects represented in the row has its own identity, and others depend on that. In USERS table that contain address infor- the previous example, the columns in the mation are dependent on the identifier of the user, the primary key of the table. An instance of Address is dependent on an instance of User. Hibernate makes the following essential distinction: ■ An object of entity type has its own database identity (primary key value). An object reference to an entity instance is persisted as a reference in the database (a foreign key value). An entity has its own lifecycle; it may exist independently of any other entity. Examples in CaveatEmptor are User, Item, and Category. ■ An object of value type has no database identity; it belongs to an entity instance and its persistent state is embedded in the table row of the owning160 CHAPTER 4 Mapping persistent classes entity. Value types don’t have identifiers or identifier properties. The lifespan of a value type instance is bounded by the lifespan of the owning entity instance. A value type doesn’t support shared references: If two users live in the same apartment, they each have a reference to their own homeAd- dress instance. The most obvious value types are classes like Strings and Integers, but all JDK classes are considered value types. User-defined classes can also be mapped as value types; for example, CaveatEmptor has Address and MonetaryAmount. Identification of entities and value types in your domain model isn’t an ad hoc task but follows a certain procedure. 4.1.3 Identifying entities and value types You may find it helpful to add stereotype information to your UML class diagrams so you can immediately see and distinguish entities and value types. This practice also forces you to think about this distinction for all your classes, which is a first step to an optimal mapping and well-performing persistence layer. See figure 4.1 for an example. The Item and User classes are obvious entities. They each have their own iden- tity, their instances have references from many other instances (shared refer- ences), and they have independent lifecycles. Identifying the Address as a value type is also easy: A particular Address instance is referenced by only a single User instance. You know this because the association has been created as a composition, where the User instance has been made fully responsible for the lifecycle of the referenced Address instance. Therefore, Address objects can’t be referenced by anyone else and don’t need their own identity. The Bid class is a problem. In object-oriented modeling, you express a compo- sition (the association between Item and Bid with the diamond), and an Item manages the lifecycles of all the Bid objects to which it has a reference (it’s a col- lection of references). This seems reasonable, because the bids would be useless if Figure 4.1 Stereotypes for entities and value types have been added to the diagram.Mapping entities with identity 161 an Item no longer existed. But at the same time, there is another association to Bid: An Item may hold a reference to its successfulBid. The successful bid must also be one of the bids referenced by the collection, but this isn’t expressed in the UML. In any case, you have to deal with possible shared references to Bid instances, so the Bid class needs to be an entity. It has a dependent lifecycle, but it must have its own identity to support shared references. You’ll often find this kind of mixed behavior; however, your first reaction should be to make everything a value-typed class and promote it to an entity only when absolutely necessary. Try to simplify your associations: Collections, for exam- ple, sometimes add complexity without offering any advantages. Instead of map- Bid references, you can write a query to obtain all ping a persistent collection of the bids for an Item (we’ll come back to this point again in chapter 7). As the next step, take your domain model diagram and implement POJOs for all entities and value types. You have to take care of three things: ■ Shared references—Write your POJO classes in a way that avoids shared refer- ences to value type instances. For example, make sure an Address object can be referenced by only one User. For example, make it immutable and enforce the relationship with the Address constructor. ■ Lifecycle dependencies—As discussed, the lifecycle of a value-type instance is bound to that of its owning entity instance. If a User object is deleted, its Address dependent object(s) have to be deleted as well. There is no notion or keyword for this in Java, but your application workflow and user interface must be designed to respect and expect lifecycle dependencies. Persistence metadata includes the cascading rules for all dependencies. ■ Identity—Entity classes need an identifier property in almost all cases. User- defined value-type classes (and JDK classes) don’t have an identifier prop- erty, because instances are identified through the owning entity. We’ll come back to class associations and lifecycle rules when we discuss more advanced mappings later in the book. However, object identity is a subject you have to understand at this point. 4.2 Mapping entities with identity It’s vital to understand the difference between object identity and object equality before we discuss terms like database identity and the way Hibernate manages identity. Next, we explore how object identity and equality relate to database (pri- mary key) identity. 162 CHAPTER 4 Mapping persistent classes 4.2.1 Understanding Java identity and equality Java developers understand the difference between Java object identity and equal- ity. Object identity, ==, is a notion defined by the Java virtual machine. Two object references are identical if they point to the same memory location. On the other hand, object equality is a notion defined by classes that imple- equals() method, sometimes also referred to as equivalence. Equiva- ment the lence means that two different (nonidentical) objects have the same value. Two String are equal if they represent the same sequence of different instances of characters, even though they each have their own location in the memory space String is a spe- of the virtual machine. (If you’re a Java guru, we acknowledge that cial case. Assume we used a different class to make the same point.) Persistence complicates this picture. With object/relational persistence, a per- sistent object is an in-memory representation of a particular row of a database table. Along with Java identity (memory location) and object equality, you pick up database identity (which is the location in the persistent data store). You now have three methods for identifying objects: ■ Objects are identical if they occupy the same memory location in the JVM. This can be checked by using the == operator. This concept is known as object identity. ■ Objects are equal if they have the same value, as defined by the equals(Object o) method. Classes that don’t explicitly override this method inherit the implementation defined by java.lang.Object, which compares object identity. This concept is known as equality. ■ Objects stored in a relational database are identical if they represent the same row or, equivalently, if they share the same table and primary key value. This concept is known as database identity. We now need to look at how database identity relates to object identity in Hiber- nate, and how database identity is expressed in the mapping metadata. 4.2.2 Handling database identity Hibernate exposes database identity to the application in two ways: ■ The value of the identifier property of a persistent instance ■ The value returned by Session.getIdentifier(Object entity) Mapping entities with identity 163 Adding an identifier property to entities The identifier property is special—its value is the primary key value of the data- base row represented by the persistent instance. We don’t usually show the identi- fier property in the domain model diagrams. In the examples, the identifier id. If myCategory is an instance of Category, calling property is always named myCategory.getId() returns the primary key value of the row represented by myCategory in the database. Let’s implement an identifier property for the Category class: public class Category private Long id; ... public Long getId() return this.id; private void setId(Long id) this.id = id; ... Should you make the accessor methods for the identifier property private scope or public? Well, database identifiers are often used by the application as a convenient handle to a particular instance, even outside the persistence layer. For example, it’s common for web applications to display the results of a search screen to the user as a list of summary information. When the user selects a particular element, the application may need to retrieve the selected object, and it’s common to use a lookup by identifier for this purpose—you’ve probably already used identifiers this way, even in applications that rely on JDBC. It’s usually appropriate to fully expose the database identity with a public identifier property accessor. On the other hand, you usually declare the setId() method private and let Hibernate generate and set the identifier value. Or, you map it with direct field access and implement only a getter method. (The exception to this rule is classes with natural keys, where the value of the identifier is assigned by the application before the object is made persistent instead of being generated by Hibernate. We discuss natural keys in chapter 8.) Hibernate doesn’t allow you to change the identifier value of a persistent instance after it’s first assigned. A pri- mary key value never changes—otherwise the attribute wouldn’t be a suitable primary key candidate 164 CHAPTER 4 Mapping persistent classes The Java type of the identifier property, java.lang.Long in the previous exam- ple, depends on the primary key type of the CATEGORY table and how it’s mapped in Hibernate metadata. Mapping the identifier property A regular (noncomposite) identifier property is mapped in Hibernate XML files with the id element: class name="Category" table="CATEGORY" id name="id" column="CATEGORY_ID" type="long" generator class="native"/ /id ... /class The identifier property is mapped to the primary key column CATEGORY_ID of the table CATEGORY. The Hibernate type for this property is long, which maps to a BIGINT column type in most databases and which has also been chosen to match the type of the identity value produced by the native identifier generator. (We discuss identifier generation strategies in the next section.) For a JPA entity class, you use annotations in the Java source code to map the identifier property: Entity Table(name="CATEGORY") public class Category private Long id; ... Id GeneratedValue(strategy = GenerationType.AUTO) Column(name = "CATEGORY_ID") public Long getId() return this.id; private void setId(Long id) this.id = id; ... The Id annotation on the getter method marks it as the identifier property, and GeneratedValue with the GenerationType.AUTO option translates into a native identifier generation strategy, like the native option in XML Hibernate map- pings. Note that if you don’t define a strategy, the default is also Generation-Mapping entities with identity 165 Type.AUTO, so you could have omitted this attribute altogether. You also specify a database column—otherwise Hibernate would use the property name. The map- ping type is implied by the Java property type, java.lang.Long. Of course, you can also use direct field access for all properties, including the database identifier: Entity Table(name="CATEGORY") public class Category Id GeneratedValue Column(name = "CATEGORY_ID") private Long id; ... public Long getId() return this.id; ... Mapping annotations are placed on the field declaration when direct field access is enabled, as defined by the standard. Whether field or property access is enabled for an entity depends on the posi- tion of the mandatory Id annotation. In the preceding example, it’s present on a field, so all attributes of the class are accessed by Hibernate through fields. The example before that, annotated on the getId() method, enables access to all attributes through getter and setter methods. Alternatively, you can use JPA XML descriptors to create your identifier mapping: entity class="auction.model.Category" access="FIELD" table name="CATEGORY"/ attributes id name="id" generated-value strategy="AUTO"/ /id ... /attributes /entity In addition to operations for testing Java object identity, (a == b), and object equality, ( a.equals(b) ), you may now use a.getId().equals( b.getId() ) to test database identity. What do these notions have in common? In what situa- tions do they all return true? The time when all are true is called the scope of166 CHAPTER 4 Mapping persistent classes guaranteed object identity; and we’ll come back to this subject in chapter 9, sec- tion 9.2, “Object identity and equality.” Using database identifiers in Hibernate is easy and straightforward. Choosing a good primary key (and key-generation strategy) may be more difficult. We discuss this issue next. 4.2.3 Database primary keys Hibernate needs to know your preferred strategy for generating primary keys. First, though, let’s define primary key. Selecting a primary key The candidate key is a column or set of columns that could be used to identify a particular row in a table. To become a primary key, a candidate key must satisfy the following properties: ■ Its value (for any column of the candidate key) is never null. ■ Each row has a unique value. ■ The value of a particular row never changes. If a table has only one identifying attribute, it’s, by definition, the primary key. However, several columns or combinations of columns may satisfy these proper- ties for a particular table; you choose between candidate keys to decide the best primary key for the table. Candidate keys not chosen as the primary key should be declared as unique keys in the database. Many legacy SQL data models use natural primary keys. A natural key is a key with business meaning: an attribute or combination of attributes that is unique by virtue of its business semantics. Examples of natural keys are the U.S. Social Secu- rity Number and Australian Tax File Number. Distinguishing natural keys is sim- ple: If a candidate key attribute has meaning outside the database context, it’s a natural key, whether or not it’s automatically generated. Think about the applica- tion users: If they refer to a key attribute when talking about and working with the application, it’s a natural key. Experience has shown that natural keys almost always cause problems in the long run. A good primary key must be unique, constant, and required (never null or unknown). Few entity attributes satisfy these requirements, and some that do can’t be efficiently indexed by SQL databases (although this is an implementation detail and shouldn’t be the primary motivation for or against a particular key). InMapping entities with identity 167 addition, you should make certain that a candidate key definition can never change throughout the lifetime of the database before making it a primary key. Changing the value (or even definition) of a primary key, and all foreign keys that refer to it, is a frustrating task. Furthermore, natural candidate keys can often be found only by combining several columns in a composite natural key. These com- posite keys, although certainly appropriate for some relations (like a link table in a many-to-many relationship), usually make maintenance, ad-hoc queries, and schema evolution much more difficult. For these reasons, we strongly recommend that you consider synthetic identifi- ers, also called surrogate keys. Surrogate keys have no business meaning—they’re unique values generated by the database or application. Application users ideally don’t see or refer to these key values; they’re part of the system internals. Intro- ducing a surrogate key column is also appropriate in a common situation: If there are no candidate keys, a table is by definition not a relation as defined by the rela- tional model—it permits duplicate rows—and so you have to add a surrogate key column. There are a number of well-known approaches to generating surrogate key values. Selecting a key generator Hibernate has several built-in identifier-generation strategies. We list the most use- ful options in table 4.1. Table 4.1 Hibernate’s built-in identifier-generator modules Generator JPA Options Description name GenerationType native AUTO – The native identity generator picks other identity generators like identity, sequence, or hilo, depending on the capa- bilities of the underlying database. Use this generator to keep your mapping metadata por- table to different database management sys- tems. identity IDENTITY – This generator supports identity columns in DB2, MySQL, MS SQL Server, Sybase, and HypersonicSQL. The returned identifier is of type long, short, or int.168 CHAPTER 4 Mapping persistent classes Table 4.1 Hibernate’s built-in identifier-generator modules (continued) Generator JPA Options Description name GenerationType sequence SEQUENCE sequence, This generator creates a sequence in DB2, PostgreSQL, Oracle, SAP DB, or Mckoi; or a parameters generator in InterBase is used. The returned identifier is of type long, short, or int. Use the sequence option to define a catalog name for the sequence (hibernate_ sequence is the default) and parameters if you need additional settings creating a sequence to be added to the DDL. (Not avail- – At Hibernate startup, this generator reads the increment able) maximum (numeric) primary key column value of the table and increments the value by one each time a new row is inserted. The gener- ated identifier is of type long, short, or int. This generator is especially efficient if the single-server Hibernate application has exclusive access to the database but should not be used in any other scenario. (Not avail- A high/low algorithm is an efficient way to gen- hilo table, column, able) max_lo erate identifiers of type long, given a table and column (by default hibernate_unique_key and next, respectively) as a source of high values. The high/low algorithm generates identifiers that are unique only for a particular database. High values are retrieved from a global source and are made unique by adding a local low value. This algorithm avoids congestion when a sin- gle source for identifier values has to be accessed for many inserts. See “Data Model- ing 101” (Ambler, 2002) for more information about the high/low approach to unique identifi- ers. This generator needs to use a separate database connection from time to time to retrieve high values, so it isn’t supported with user-supplied database connections. In other words, don’t use it with sessionFactory.openSession(myCo nnection). The max_lo option defines how many low values are added until a new high value is fetched. Only settings greater than 1 are sensible; the default is 32767 (Short.MAX_VALUE). Mapping entities with identity 169 Table 4.1 Hibernate’s built-in identifier-generator modules (continued) Generator JPA Options Description name GenerationType seqhilo (Not avail- sequence, This generator works like the regular hilo able) generator, except it uses a named database parameters, sequence to generate high values. max_lo (JPA TABLE table, catalog, Much like Hibernate’s hilo strategy, TABLE relies on a database table that holds the last- only) schema, generated integer primary key value, and each pkColumnName, generator is mapped to one row in this table. valueColumnNam Each row has two columns: pkColumnName e, and valueColumnName. The pkColumn- pkColumnValue, Value assigns each row to a particular gen- allocationSize erator, and the value column holds the last retrieved primary key. The persistence provider allocates up to allocationSize integers in each turn. uuid.hex (Not avail- separator This generator is a 128-bit UUID (an algorithm able) that generates identifiers of type string, unique within a network). The IP address is used in combination with a unique timestamp. The UUID is encoded as a string of hexadeci- mal digits of length 32, with an optional separator string between each component of the UUID representation. Use this generator strategy only if you need globally unique identi- fiers, such as when you have to merge two databases regularly. guid (Not avail- - This generator provides a database-generated able) globally unique identifier string on MySQL and SQL Server. select (Not avail- key This generator retrieves a primary key able) assigned by a database trigger by selecting the row by some unique key and retrieving the primary key value. An additional unique candi- date key column is required for this strategy, and the key option has to be set to the name of the unique key column. 170 CHAPTER 4 Mapping persistent classes Some of the built-in identifier generators can be configured with options. In a native Hibernate XML mapping, you define options as pairs of keys and values: id column="MY_ID" generator class="sequence" parameter name="sequence"MY_SEQUENCE/parameter parameter name="parameters" INCREMENT BY 1 START WITH 1 /parameter /generator /id You can use Hibernate identifier generators with annotations, even if no direct annotation is available: Entity org.hibernate.annotations.GenericGenerator( name = "hibernate-uuid", strategy = "uuid" ) class name MyEntity Id GeneratedValue(generator = "hibernate-uuid") Column(name = "MY_ID") String id; The GenericGenerator Hibernate extension can be used to give a Hibernate identifier generator a name, in this case hibernate-uuid. This name is then refer- generator attribute. enced by the standardized This declaration of a generator and its assignment by name also must be applied for sequence- or table-based identifier generation with annotations. Imag- ine that you want to use a customized sequence generator in all your entity classes. Because this identifier generator has to be global, it’s declared in orm.xml: sequence-generator name="mySequenceGenerator" sequence-name="MY_SEQUENCE" initial-value="123" allocation-size="20"/ This declares that a database sequence named MY_SEQUENCE with an initial value of 123 can be used as a source for database identifier generation, and that the per- sistence engine should obtain 20 values every time it needs identifiers. (Note, though, that Hibernate Annotations, at the time of writing, ignores the initial- Value setting.) To apply this identifier generator for a particular entity, use its name: Class mapping options 171 Entity class name MyEntity Id GeneratedValue(generator = "mySequenceGenerator") String id; If you declared another generator with the same name at the entity level, before the class keyword, it would override the global identifier generator. The same TableGenerator. approach can be used to declare and apply a You aren’t limited to the built-in strategies; you can create your own identifier IdentifierGenerator interface. As generator by implementing Hibernate’s always, it’s a good strategy to look at the Hibernate source code of the existing identifier generators for inspiration. It’s even possible to mix identifier generators for persistent classes in a single domain model, but for nonlegacy data we recommend using the same identifier generation strategy for all entities. For legacy data and application-assigned identifiers, the picture is more com- plicated. In this case, we’re often stuck with natural keys and especially composite keys. A composite key is a natural key that is composed of multiple table columns. Because composite identifiers can be a bit more difficult to work with and often only appear on legacy schemas, we only discuss them in the context of chapter 8, section 8.1, “Integrating legacy databases.” We assume from now on that you’ve added identifier properties to the entity classes of your domain model, and that after you completed the basic mapping of each entity and its identifier property, you continued to map value-typed proper- ties of the entities. However, some special options can simplify or enhance your class mappings. 4.3 Class mapping options If you check the hibernate-mapping and class elements in the DTD (or the reference documentation), you’ll find a few options we haven’t discussed so far: ■ Dynamic generation of CRUD SQL statements ■ Entity mutability control ■ Naming of entities for querying ■ Mapping package names ■ Quoting keywords and reserved database identifiers ■ Implementing database naming conventions 172 CHAPTER 4 Mapping persistent classes 4.3.1 Dynamic SQL generation By default, Hibernate creates SQL statements for each persistent class on startup. These statements are simple create, read, update, and delete operations for read- ing a single row, deleting a row, and so on. How can Hibernate create an UPDATE statement on startup? After all, the col- umns to be updated aren’t known at this time. The answer is that the generated SQL statement updates all columns, and if the value of a particular column isn’t modified, the statement sets it to its old value. In some situations, such as a legacy table with hundreds of columns where the SQL statements will be large for even the simplest operations (say, only one col- umn needs updating), you have to turn off this startup SQL generation and switch to dynamic statements generated at runtime. An extremely large number of enti- ties can also impact startup time, because Hibernate has to generate all SQL state- CRUD upfront. Memory consumption for this query statement cache ments for will also be high if a dozen statements must be cached for thousands of entities (this isn’t an issue, usually). Two attributes for disabling CRUD SQL generation on startup are available on class mapping element: the class name="Item" dynamic-insert="true" dynamic-update="true" ... /class The dynamic-insert attribute tells Hibernate whether to include null property values in an SQL INSERT, and the dynamic-update attribute tells Hibernate whether to include unmodified properties in the SQL UPDATE. If you’re using JDK 5.0 annotation mappings, you need a native Hibernate annotation to enable dynamic SQL generation: Entity org.hibernate.annotations.Entity( dynamicInsert = true, dynamicUpdate = true ) public class Item ... The second Entity annotation from the Hibernate package extends the JPA annotation with additional options, including dynamicInsert and dynamicUpdate. Sometimes you can avoid generating any UPDATE statement, if the persistent class is mapped immutable. Class mapping options 173 4.3.2 Making an entity immutable Instances of a particular class may be immutable. For example, in CaveatEmptor, a Bid made for an item is immutable. Hence, no UPDATE statement ever needs to BID table. Hibernate can also make a few other optimizations, be executed on the such as avoiding dirty checking, if you map an immutable class with the mutable attribute set to false: hibernate-mapping default-access="field" class name="Bid" mutable="false" ... /class /hibernate-mapping A POJO is immutable if no public setter methods for any properties of the class are exposed—all values are set in the constructor. Instead of private setter methods, you often prefer direct field access by Hibernate for immutable persistent classes, so you don’t have to write useless accessor methods. You can map an immutable entity using annotations: Entity org.hibernate.annotations.Entity(mutable = false) org.hibernate.annotations.AccessType("field") public class Bid ... Again, the native Hibernate Entity annotation extends the JPA annotation with additional options. We have also shown the Hibernate extension annotation AccessType here—this is an annotation you’ll rarely use. As explained earlier, the default access strategy for a particular entity class is implicit from the position of the mandatory Id property. However, you can use AccessType to force a more fine-grained strategy; it can be placed on class declarations (as in the pre- ceding example) or even on particular fields or accessor methods. Let’s have a quick look at another issue, the naming of entities for queries. 4.3.3 Naming entities for querying By default, all class names are automatically “imported” into the namespace of the Hibernate query language, HQL. In other words, you can use the short class names without a package prefix in HQL, which is convenient. However, this auto- import can be turned off if two classes with the same name exist for a given Ses- sionFactory, maybe in different packages of the domain model. If such a conflict exists, and you don’t change the default settings, Hibernate won’t know which class you’re referring to in HQL. You can turn off auto-import174 CHAPTER 4 Mapping persistent classes of names into the HQL namespace for particular mapping files with the auto- import="false" setting on the hibernate-mapping root element. Entity names can also be imported explicitly into the HQL namespace. You can even import classes and interfaces that aren’t explicitly mapped, so a short name can be used in polymorphic HQL queries: hibernate-mapping import class="auction.model.Auditable" rename="IAuditable"/ /hibernate-mapping You can now use an HQL query such as from IAuditable to retrieve all persistent instances of classes that implement the auction.model.Auditable interface. (Don’t worry if you don’t know whether this feature is relevant to you at this point; we’ll get back to queries later in the book.) Note that the import ele- ment, like all other immediate child elements of hibernate-mapping, is an application-wide declaration, so you don’t have to (and can’t) duplicate this in other mapping files. With annotations, you can give an entity an explicit name, if the short name would result in a collision in the JPA QL or HQL namespace: Entity(name="AuctionItem") public class Item ... Now let’s consider another aspect of naming: the declaration of packages. 4.3.4 Declaring a package name All the persistent classes of the CaveatEmptor application are declared in the Java package auction.model. However, you don’t want to repeat the full package name whenever this or any other class is named in an association, subclass, or component mapping. Instead, specify a package attribute: hibernate-mapping package="auction.model" classname="Item" table="ITEM" ... /class /hibernate-mapping Now all unqualified class names that appear in this mapping document will be prefixed with the declared package name. We assume this setting in all mapping examples in this book and use unqualified names for CaveatEmptor model classes. Names of classes and tables must be selected carefully. However, a name you’ve chosen may be reserved by the SQL database system, so the name has to be quoted.Class mapping options 175 4.3.5 Quoting SQL identifiers By default, Hibernate doesn’t quote table and column names in the generated SQL. This makes the SQL slightly more readable, and it also allows you to take SQL databases are case insensitive when compar- advantage of the fact that most ing unquoted identifiers. From time to time, especially in legacy databases, you encounter identifiers with strange characters or whitespace, or you wish to force case sensitivity. Or, if you rely on Hibernate’s defaults, a class or property name in Java may be automatically translated to a table or column name that isn’t allowed in your database management system. For example, the User class is mapped to a USER table, which is usually a reserved keyword in SQL databases. Hibernate doesn’t know the SQL keywords of any DBMS product, so the database system throws an exception at startup or runtime. If you quote a table or column name with backticks in the mapping document, SQL. The following prop- Hibernate always quotes this identifier in the generated erty declaration forces Hibernate to generate SQL with the quoted column name "DESCRIPTION". Hibernate also knows that Microsoft SQL Server needs the varia- tion DESCRIPTION and that MySQL requires `DESCRIPTION`. property name="description" column="`DESCRIPTION`"/ There is no way, apart from quoting all table and column names in backticks, to force Hibernate to use quoted identifiers everywhere. You should consider renam- ing tables or columns with reserved keyword names whenever possible. Quoting with backticks works with annotation mappings, but it’s an implementation detail of Hibernate and not part of the JPA specification. 4.3.6 Implementing naming conventions We often encounter organizations with strict conventions for database table and column names. Hibernate provides a feature that allows you to enforce naming standards automatically. Suppose that all table names in CaveatEmptor should follow the pattern CE_table name. One solution is to manually specify a table attribute on all class and collection elements in the mapping files. However, this approach is time-consuming and easily forgotten. Instead, you can implement Hibernate’s NamingStrategy interface, as in listing 4.1. 176 CHAPTER 4 Mapping persistent classes Listing 4.1 NamingStrategy implementation public class CENamingStrategy extends ImprovedNamingStrategy public String classToTableName(String className) return StringHelper.unqualify(className); public String propertyToColumnName(String propertyName) return propertyName; public String tableName(String tableName) return "CE_" + tableName; public String columnName(String columnName) return columnName; public String propertyToTableName(String className, String propertyName) return "CE_" + classToTableName(className) + '_' + propertyToColumnName(propertyName); You extend the ImprovedNamingStrategy, which provides default implementa- tions for all methods of NamingStrategy you don’t want to implement from scratch (look at the API documentation and source). The classToTableName() method is called only if a class mapping doesn’t specify an explicit table name. The propertyToColumnName() method is called if a property has no explicit column name. The tableName() and columnName() methods are called when an explicit name is declared. If you enable this CENamingStrategy, the class mapping declaration class name="BankAccount" results in CE_BANKACCOUNT as the name of the table. However, if a table name is specified, like this, class name="BankAccount" table="BANK_ACCOUNT" then CE_BANK_ACCOUNT is the name of the table. In this case, BANK_ACCOUNT is passed to the tableName() method.