Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

manning Hibernate in Action phần 10 pdf
Nội dung xem thử
Mô tả chi tiết
Licensed to Jose Carlos Romero Figueroa <[email protected]>
Development processes 349
Good ORM software comes bundled with a set of tools, and so does Hibernate. In
this chapter, we’ll discuss the Hibernate toolset. These tools can automatically generate mapping metadata, SQL database schemas, and even Java POJO source code.
However, you have to use the right tool for your specific development process.
9.1 Development processes
In some projects, the development of a domain model is driven by developers analyzing the business domain in object-oriented terms. In others, it’s heavily influenced by an existing relational data model: either a legacy database or a brand-new
schema designed by a professional data modeler.
Since different projects start from different points, we need to consider different development scenarios and the different tools that may be used in each case.
An overview of the tools and the artifacts they use as source and output is shown in
figure 9.1. You may want to refer to this diagram while reading this chapter.
NOTE Note that AndroMDA, a tool that generates POJO source code from UML
diagram files, isn’t strictly considered part of the common Hibernate
toolset; hence we don’t discuss it in this chapter. See the community area
on the Hibernate website for more information about the Hibernate
modules in AndroMDA.
Before we begin looking closely at any of the particular tools you can use with
Hibernate, we’ll briefly survey the main scenarios and mention the tools that are
most appropriate to each.
Mapping
Metadata
Database
Schema
POJO
Java Source
SchemaExport
(hbm2ddl)
XDoclet
XML/XMI
AndroMDA
CodeGenerator
(hbm2java)
Middlegen
UML Model
Figure 9.1
Input and output of the tools
used for Hibernate development
Licensed to Jose Carlos Romero Figueroa <[email protected]>
350 CHAPTER 9
Using the toolset
9.1.1 Top down
In top-down development, you start with an existing Java domain model (ideally implemented with POJOs/JavaBeans) and complete freedom with respect to the database schema. You must create a mapping document—either manually using a text
editor (recommended is an IDE with XML auto-completion) or automatically using
XDoclet—and then let Hibernate’s hbm2ddl tool generate the database schema. In
the absence of an existing data model, this is the most comfortable development
style for most Java developers. You can even use the Hibernate tools to automatically refresh the database schema on every application restart in development.
9.1.2 Bottom up
Conversely, bottom-up development begins with an existing database schema and data
model. In this case, the easiest way to proceed is to use Middlegen to generate
Hibernate mapping documents and then run the hbm2java tool and generate skeletal POJO persistent classes. You’ll usually have to enhance and modify the generated Hibernate mapping by hand, because not all class association details and Javaspecific meta-information can be automatically generated from an SQL schema.
9.1.3 Middle out (metadata oriented)
Neither Java classes (without XDoclet annotations) nor DDL schemas contain
enough information to be able to completely deduce an ORM. Hence, if you wish
to generate the Hibernate mapping document instead of writing it by hand, you’ll
need extra input from the user. In the case of XDoclet, this information is provided
by XDoclet attributes embedded in the source code. In the case of Middlegen, it’s
provided via the Middlegen GUI.
On the other hand, the mapping document does provide sufficient information
to completely deduce the DDL schema and to generate working JavaBeans. Furthermore, the mapping document isn’t too verbose. So, you may prefer middle-out
development, where you begin with a handwritten Hibernate mapping document
and generate the DDL using hbm2ddl and Java classes using hbm2java.
9.1.4 Meet in the middle
The most difficult scenario combines existing Java classes and an existing relational schema. In this case, there is little that the Hibernate toolset can do to help.
It isn’t possible to map arbitrary Java domain models to a given schema, so this scenario usually requires at least some refactoring of the Java classes, database
Licensed to Jose Carlos Romero Figueroa <[email protected]>
Automatic schema generation 351
schema, or both. The mapping document must almost certainly be written by hand
(although it might be possible to use XDoclet). This is an incredibly painful scenario that is, fortunately, exceedingly rare.
9.1.5 Roundtripping
The notion of roundtripping is that any one of the three kinds of artifacts (Java
classes, mapping documents, database schema) should be sufficient to reproduce
the other two. Each tool should be completely reversible. You’ve already seen that
this isn’t the case. At the very least, you must add XDoclet annotations to the Java
classes. Worse, it’s never possible to fully reproduce the Java domain model or ORM
from only the database schema.
Nevertheless, the Hibernate team is attempting to achieve a slightly less ambitious goal for the Hibernate toolset. Suppose you start with an existing database
schema. Then the following steps should reproduce this schema exactly, with minimal user intervention:
1 Use Middlegen to create a mapping document
2 Use hbm2java to generate annotated Java classes
3 Use XDoclet to regenerate the mapping document
4 Use hbm2ddl to generate the DDL
At the time of this writing, there is still work to be done before this approach works
perfectly, because it involves many different tools and metamodel conversions.
We’ll now look more closely at each of the tools we’ve mentioned, starting with
hbm2ddl. This tool is used to automatically generate SQL DDL from Hibernate mapping metadata. We assume that you’ve already created some POJO persistent classes
and the relevant Hibernate mappings and are now looking for a way to simplify the
creation of the schema in the database.
9.2 Automatic schema generation
Schemas for SQL-based database management systems are written in the SQL
DDL. This includes well-known statements such as CREATE and ALTER.
The tool used for the generation process is called hbm2ddl. Its class is
net.sf.hibernate.tool.hbm2ddl.SchemaExport; hence it’s also sometimes called
SchemaExport.
Licensed to Jose Carlos Romero Figueroa <[email protected]>
352 CHAPTER 9
Using the toolset
NOTE The Hibernate extensions package—You may have noticed that hbm2ddl
resides inside the main Hibernate distribution and isn’t packaged with
the other tools in HibernateExtensions. The Hibernate team decided
that hbm2ddl is much closer to the core functionality of Hibernate than
any of the other tools and should be bundled with Hibernate itself. In
addition, you can run hbm2ddl from an application to automatically generate a database schema at runtime. This ability is especially useful if
you’d like to initialize the database every time the application in development restarts.
In Hibernate, the prerequisite for automatically generating SQL DDL is always a
Hibernate mapping metadata definition in XML. We assume that you’ve designed
and implemented your POJO classes and written mapping metadata, but you probably haven’t paid much attention to database-specific details (like table and column names).
Some special elements and attributes can be used in the mapping files; most of
them are relevant only for a customized schema. Hibernate tries to use sensible
defaults if you don’t specify your own names and strategies; however, be warned
that a professional DBA might not accept this default schema without manual
changes. Nevertheless, the defaults may be satisfactory for a development or prototype environment.
9.2.1 Preparing the mapping metadata
In this example, we’ve marked up the mapping for the Item class with hbm2ddl-specific attributes and elements. These optional definitions integrate seamlessly with
the other mapping elements, as you can see in listing 9.1.
Listing 9.1 Additional elements in the Item mapping for SchemaExport
<class name="Item" table="ITEM">
<id name="id" type="string">
<column name="ITEM_ID" sql-type="char(32)"/> B
<generator class="uuid.hex"/>
</id>
<property name="name" type="string">
<column name="NAME"
not-null="true"
length="255"
index="IDX_ITEMNAME"/> C
</property>
<property name="description"
type="string"
Licensed to Jose Carlos Romero Figueroa <[email protected]>
Automatic schema generation 353
column="DESCRIPTION"
length="4000"/> D
<property name="initialPrice"
type="customtype.MonetaryAmount">
<column name="INITIAL_PRICE" check="INITIAL_PRICE > 0"/> E
<column name="INITIAL_PRICE_CURRENCY"/>
</property>
<set name="categories" table="CATEGORY_ITEM" cascade="none">
<key
<column="ITEM_ID" sql-type="char(32)"/> F
</key>
<many-to-many class="Category">
<column="CATEGORY_ID" sql-type="char(32)/>
</many-to-many>
</set>
...
</class>
B hbm2ddl automatically generates a VARCHAR typed column if a property (even the
identifier property) is of mapping type string. We know the identifier generator
uuid.hex always generates strings that are 32 characters long; so, we use a CHAR
SQL type and also set its size fixed at 32 characters. The nested <column> element
is required for this declaration because there is no attribute to specify the SQL
datatype on the <id> element.
C The column, not-null, and length attributes are also available on the <property>
element, but we want to create an additional index in the database, hence we
again use a nested <column> element. This index will speed our searches for items
by name. If we reuse the same index name on other property mappings, we can
create an index that includes multiple database columns. The value of this
attribute is also used to name the index in the database catalog.
D For the description field, we chose the lazy approach, using the attributes on the
<property> element instead of a <column> element. The DESCRIPTION column will
be generated as VARCHAR(4000).
E The custom user-defined type MonetaryAmount requires two database columns to
work with. We have to use the <column> element. The check attribute triggers the
creation of a check constraint; the value in that column must match the given arbitrary SQL expression. Note that there is also a check attribute for the <class> element, which is useful for multicolumn check constraints.
Licensed to Jose Carlos Romero Figueroa <[email protected]>
354 CHAPTER 9
Using the toolset
F A <column> element can also be used to declare the foreign key fields in an association mapping. Otherwise, the columns of our association table CATEGORY_ITEM
would be VARCHAR(32) instead of the more appropriate CHAR(32) type.
We’ve grouped all attributes relevant for schema generation in table 9.1; some of
them weren’t included in the previous Item mapping example.
Table 9.1 XML mapping attributes for hbm2ddl
Attribute Value Description
column string Usable in most mapping elements; declares the name of the SQL
column. hbm2ddl (and Hibernate’s core) defaults to the name of
the Java property) if the column attribute is omitted and no
nested <column> element is present. This behavior may be
changed by implementing a custom NamingStrategy; see the
section “Naming conventions” in chapter 3.
not-null true/false Forces the generation of a NOT NULL column constraint. Available
as an attribute on most mapping elements and also on the dedicated <column> element.
unique true/false Forces the generation of a single-column UNIQUE constraint.
Available for various mapping elements.
length integer Can be used to define a "length" of a datatype. For example,
length="4000" for a string mapped property generates a
VARCHAR(4000) column. This attribute is also used to define
the precision of decimal types.
index string Defines the name of a database index that can be shared by multiple elements. An index on a single column is also possible. Only
available with the <column> element.
unique-key string Enables unique constraints involving multiple database columns.
All elements using this attribute must share the same constraint
name to be part of a single constraint definition. This is a <column> element-only attribute.
sql-type string Overrides hbm2ddl’s automatic detection of the SQL datatype;
useful for database specific data types. Be aware that this effectively prevents database independence: hbm2ddl will automatically generate a VARCHAR or VARCHAR2 (for Oracle), but it will
always use a declared SQL-type instead, if present. This attribute
can only be used with the dedicated <column> element.
foreign-key string Names a foreign-key constraint, available for <many-to-one>,
<one-to-one>, <key>, and <many-to-many> mapping elements. Note that inverse="true" sides of an association mapping won’t be considered for foreign key naming, only the noninverse side. If no names are provided, Hibernate generates
unique random names.