 |
J2EE Archives
Need a Primary Key? Let Me Show You the Ways
Posted by bleonard on December 05, 2006 at 07:15 AM | Permalink
| Comments (1)
When you're adding a table record and need a primary key, you can choose to generate one yourself or let the Java Persistence API do that for you. In this entry, I'm going to review a couple of the alternatives the JPA provides you for creating primary keys.
The JPA Options
If you want JPA to generate a primary key for you, you just need to add an @GeneratedValue along with the @Id annotation:
23 @Entity
24 public class NewEntity implements Serializable {
25
26 @Id
27 @GeneratedValue
28 private Long id;
Using this simple approach, the persistence provider is going to select the key generation strategy, and it is equivalent to setting the following:
27 @GeneratedValue(strategy = GenerationType.AUTO)
The persistence provider will then choose from one of the following three generation options:
- TABLE - the persistence provider uses a database table for managing keys.
- SEQUENCE - the persistence provider uses a databases sequence for key generation. The database must support Sequences.
- IDENTITY - the persistence provider defers to the database for key generation. The database must support the IDENTITY column type.
For this blog I'm using Oracle's TopLink Essentials and Derby as my database. Although I may be restricted to how TopLink Essentials behaves or Derby's capabilities, the concepts discussed here apply to all persistence providers and databases.
Setting Things Up
To continue we need NetBeans 5.5 and the Java EE Application Server 9.0 (which bundles both TopLink Essentials and Derby). If you need both, just download and install the bundle.
Once installed, we're going to up the application server's logging level so we can see the SQL generated by TopLink. Follow these steps:
- Switch to the Runtime window (Ctrl+5).
- Expand the Servers node and right-click the Sun Java System Application Server node.
- Select View Admin Console.
- Unless you changed it, the default User Name should be admin. The default Password: adminadmin. Login.
- Click the Application Server node.
- Select the Logging tab.
- Select the Log Levels sub-tab.
- Set the Persistence level to FINE:
- Click Save.
Going on AUTO
- Create a new Web Application Project named KeyGen.
- Start the Entity Class wizard (Ctrl+N, Persistence > Entity Class)
- Leave the Class Name as NewEntity and Set the Package to Entity
- Click Create Persistence Unit
- Select jdbc/sample as the Data Source.
- Change the Table Generation Strategy to Drop and Create. (This is because we will be regenerating the table over and over again as we change primary key generation strategies)
- Click Create and Finish
You now have a basic entity class that starts like the following:
23 @Entity
24 public class NewEntity implements Serializable {
25
26 @Id
27 @GeneratedValue(strategy = GenerationType.AUTO)
28 private Long id;
Very similar to the code segment above, except for the default generation strategy is specified.
- To make the table just a bit more interesting, add another attribute, for example, firstName:
30 private String firstName;
- On an empty line below the firstName attribute, press Ctrl+Space to create a getter and setter for firstName:
- Switch to the Projects window (Ctrl+1), right-click the KeyGen project and select Deploy Project.
As the project is deployed, you'll see the following SQL in the output tab (only if you've changed the server's log level to FINE as described above):

Notice 2 tables, were created, NEWENTITY and SEQUENCE. You can also see the tables in the Runtime tab (if you need to connect, the password is app):

So, which key generation strategy does TopLink use? If you guessed SEQUENCE, you're wrong. It's TABLE. SEQUENCE just happens to be the name TopLink uses as it's generated table name. Watch, let's specifically set the strategy to TABLE and see what happens.
Deciding on TABLE
Here were going to specifically set the generation strategy to TABLE.
- In NewEntity.java, change the generation type from AUTO to TABLE:
27 @GeneratedValue(strategy = GenerationType.TABLE)
- Deploy the application again and look at the SQL and the resulting tables. Nothing's changed. However, let's say we want to customize the key generation table. JPA allows us to do that using the @TableGenerator annotation.
Using @TableGenerator
Using @TableGenerator, you can customize the name of the table, the name name of the table's columns and even the value of the key field. For now, we'll just customize the table name. To do that, we create an @TableGenerator like follows:
- Add the following @TableGenerator annotation to the id field:
29 @TableGenerator(name="NE_IDGEN", table="NEWENTITY_KEYGEN")
Notice we have to assign the generator a name. This is so we can link it to the @GeneratedValue annotation.
- Add the generator argument to the @GeneratedValue annotation.
27 @Id
28 @GeneratedValue(strategy = GenerationType.TABLE, generator="NE_IDGEN")
29 @TableGenerator(name="NE_IDGEN", table="NEWENTITY_KEYGEN")
30 private Long id;
- Deploy the application and notice the key table is now NEWENTITY_KEYGEN:
Trying out IDENTITY
The IDENTITY generation strategy is a straight pass through to the database. The persistence provider does nothing.
- Change the GenerationType from TABLE to IDENTITY.
- Delete the generator argument
- Delete the @TableGenerator
- Your code should now look as follows:
27 @Id
28 @GeneratedValue(strategy = GenerationType.IDENTITY)
29 private Long id;
- Deploy the application. This time, only one SQL statement is executed. Notice the ID field is created AS IDENTITY:
Trying out SEQUENCE
Oops, Derby doesn't support Sequences, so I'll leave this one for you to experiment with on your own.
Testing the KeyGenerators
If you want to test these various generation strategies, you can create a quick user interface for your application by running the JSF Pages from Entity Class wizard. For example:
- Press Ctrl+N to start the New File wizard and select Persistence > JSF Pages from Entity Class.
- Add the NewEntity (entity) class to the Selected Entity Classes list and click Next.
- Set the package to view and click Finish.
- Press F6 to run the application.
- Select List of NewEntity.
- Select New NewEntity.
- Enter a name and click Create. Notice there's no need to worry about the primary key:


This interface will work with any of the key generation strategies, so you can easily switch back to TABLE, SEQUENCE (if your database supports it) or AUTO and test run the application again.
Using Composite Keys with JPA
Posted by bleonard on November 29, 2006 at 09:14 AM | Permalink
| Comments (14)
The Java Persistence API is beautiful. I create a class, annotate it with @Entity and @Id and I'm on my way. That is, however, assuming the Id is of a simple type (I'm a firm believer that primary keys should be of a simple type, unrelated to the data they index.). However, if you find yourself in a situation where you must use a composite key (hopefully this is only because you're connecting to some existing data set), JPA will still work for you, although it gets a bit more complex. First of all, you can declare a composite primary key using one of two annotations: @IdClass or @EmbeddedId. In this blog, I'm going to focus on the latter.
Using @EmbeddedId
A composite primary key must be represented by a primary key class. And when using the @EmbeddedId approach, it must be annotated as @Embeddable.
@Embeddable
public class ContactPK implements Serializable {
@Column(name = "FIRSTNAME", nullable = false)
private String firstname;
@Column(name = "LASTNAME", nullable = false)
private String lastname;
...
The primary key in the entity class is annoated with @EmbeddedId annotation:
@Entity
public class Contact implements Serializable {
@EmbeddedId
protected ContactPK contactPK;
...
However, it doesn't stop there. The entity class must also implement the hashcode() and equals() methods. As I mentioned in my introduction, hopefully you're only using composite keys if you already have existing tables defined that way. In the spirit of that assumption, we're going to start with a table and just use NetBeans to create our entity class.
Setting Things Up
To continue we need NetBeans 5.5 and the Java EE Application Server 9.0. If you need both, just download and install the bundle.
Creating the Table
CompositeCustomer.sql will create a table with a composite primary key populated with some sample data.
- Save the CompositeCustomer.sql file somewhere on your disk.
- Open the file in NetBeans (Ctrl+O).
- On the SQL editor's toolbar, you'll see a Connection drop-down box. Select the jdbc:derby://localhost:1527/sample [app on APP] entry.

- Click the Run SQL icon
on the right of the Connection drop-down box. This will open the Connect dialog. The password is app. Click OK to connect and run the SQL script.
- You can now view the table in the Runtime window:
Generating Entities With Composite Keys
The setup was the hard part. To create the entity class:
- Create a new Web Application project named CompositeKey.
- Add a new file (Ctrl+N) and select Persistence > Entity Classes from Database
- Select jdbc/sample as the Data Source and COMPOSITE_CUSTOMER as the table. Click Next.
- Set the Package to entity and click Create Persistence Unit.
- On the Create Persistence Unit dialog, just click Create.
- Click Finish
And you're done. The wizard created the primary key class, CompositeCustomerPK as well as the entity CompositeCustomer.

Testing the Entity
Here we'll delete our table and let JPA re-create it for us.
- Switch to the Runtime window, select the COMPOSITE_CUSTOMER table and press Delete.
- Switch to the Projects window and open up persistence.xml (under the Configuration Files folder). Change the Table Generation Strategy to Create
- Right-click the CompositeKey project and select Deploy Project. This will start the Sun Java System Application Server, if not already running, and deploy the project.
- Switch back to the Runtime window, right-click the Tables folder and select Refresh. JPA has re-created the table for us (sans the sample data, of course).
A Conversation with Seam
Posted by bleonard on November 15, 2006 at 10:51 AM | Permalink
| Comments (1)
Another one of Seam's compelling features is its ability to manage "conversations". A Seam conversation provides fine grain control over the traditional HTTP session scope so that "concurrent conversations" can occur in HTTP session, which usually occur when users open another browser window or tab. The problem is best described with an example. I've added a confirmation page to the registration application used in my previous blog entries. So consider this application use case:
I launch the application and enter my registration information:

And the Registration page takes me to a confirmation page:
However, rather than completing the transaction (or conversation), I open a new browser tab and decide to register my brother as well:
And click Register to load his confirmation page:
But before completing this 2nd transaction (conversation), I return back to the registration tab with my registration details and now decide to complete the original transaction (conversation):

Hmmm, not was I was expecting (actually, it was - but you know what I mean). Now for anyone who's done web application development, managing the HTTP Session for these scenarios can be a nightmare. Let's see how easily the Seam framework addresses this all too common problem. If you'd like to produce and fix this problem yourself, continue with the following Steps. If you just want to see the solution, jump to Step 3: Solving the Conversation Problem.
Step 1: Getting the Goods
- Download NetBeans 5.5
- Download and extract JBoss Seam 1.0.1 GA
- Download and install JEMS 1.2.0. BETA1. The JEMS installer includes JBoss AS 4.0.4GA and EJB3 CR8, both of which are needed to work with Seam 1.0.1 GA. Be sure to select the ejb3 profile during installation. Note, if you use the JEMS 1.2.0 BETA2 or 3, you may run into this issue.
- Download and extract the Registration application.
Step 2: Setting Up Your Environment
In this first step, we'll set up the environment to run our Registration application.
Add the JBoss Server to NetBeans
- Switch to the Runtime tab and right-click the Servers node to add a server.
- Select JBoss Application Server 4 from the Server drop down list. Change the name to JBoss Application Server 4.0.4.
- Complete the Add Server wizard.
- Right-click the new JBoss server node and choose Start:

Create the Seam Libraries
The Registration Project that we'll open in the next step references a class library called JBossSeam, which we'll now create using the 1.0.1 GA of Seam:
- Open the Library Manager (Tools menu) and create a new class library called JBossSeam.
- Set the Classpath to jboss-seam.jar.
- Set the Sources to the JBoss Seam src\main directory.
- Set the Javadoc to the JBoss Seam doc directory.
These libraries are now available for use by any project.
Open the Registration Project
The Registration application is a NetBeans Enterprise Application Project, which is actually comprised of 3 projects: Registration, Registration-EJBModule and Registration-WebModule. Registraiton-EJBModule and Registration-WebModule are Java EE Modules of the Registration project. Registration-EJBModule generates the EJB jar file. Registration-WebModule generates the war file and Registration generates the ear file which contains the jar and war.
- Open the Registration project. The Enterprise Application Project stores the absolute location to its Java EE Modules. So, unless you extracted your project to the exact same location as me, you will see this dialog when you open the project.

- Click Close. The Registration project will be in bold red.
- Right click the project and select Resolve Reference Problems from the context menu.

- Use the Resolve Reference Problems dialog to map each module to its project, which you'll find are subdirectories beneath the Registration directory.
- After the references are resolved, right-click the Registration project and select Open Required Projects (now that the dependencies are correct, these dependent projects will always open for you).

- You'll notice the Registration-WebModule also has a reference problem, as it references the Registration-EJBModule. Use the same steps to correct the reference.
Test Run the Registration Project
- Press F6 to run the project. This will build, package, deploy, start JBoss and launch the application in a browser for you.
You can now walk through to steps outlined in the introduction to create the "conversation problem".
Step 3: Solving the Conversation Problem
The Registration application in the example is already using Seam, it's just not using the conversation feature. In this step, we'll make a few simple changes to our application which will solve the conversation problem outlined in the introduction.
- User is a named seam component that's currently set to session scope, which matches the standard JSF session scope. Open User.java and change the ScopeType from SESSION to CONVERSATION. This will cause Seam to look for @Begin and @End tags to manage the conversation.
@Scope(ScopeType.CONVERSATION)
- Open RegisterActonBean.java and add the @Begin annotation to the confirm method and the @End annotation to the register method. It's as simple as that. The Seam framework will now create and manage a new instance of our User component for each conversation.
@Begin
public String confirm() {
return "success";
}
@End
public String register() {
- Walk through the scenario presented in the introduction above and notice how session data no longer crosses tab (or browser instance) boundaries.
|