Archive for the ‘hibernate’ Tag

“Communications of the ACM” articles …

For the last one year or so, I have been an avid reader of the “Communications of the ACM” Magazine (http://cacm.acm.org/). I find it quite refreshing that in every issue there are atleast a few articles that are relevant to every day software development and in this post, I have made a short-list of articles that I found really interesting as well as useful.

Whither Sockets : A look at the Sockets API, its origins, how it has evolved, and its drawbacks (June 2009, Vol.52, No.6).

API Design Matters : An extremely well written article on how to design APIs (May 2009, Vol. 52, No.5).

Scalable Synchronous Queues: This article is not available in its entirety on the website (need to be a member). So I have linked it to a PDF from the author’s website (May 2009, Vol. 52, No.5).

ORM in Dynamic Languages : A fascinating article on how Hibernate is used in GORM (the persistence component of Grails). So many of these ideas can be quite easily transferred over to Java and make Hibernate usage a lot easier in Java (April 2009, Vol.52, No.4)

Concurrent Programming with Erlang : Once again, a member-only accessible article, but available via ACM Queue (March 2009, Vol.52, No.3).

Happy reading !!

Hibernate Bidirectional One-To-Many Mapping via Annotations

In one of my previous posts, I had talked about handling inheritance with Hibernate Annotations. We had talked about an AccountTransaction entity that had two sub-classes, MoneyTransaction and StockTransaction. In this post, I am going to talk about how we are going to link the AccountTransaction entity with the Customer entity.

As always, all the code mentioned here is available via the Google Code Project – DalalStreet.

Let us first start by asking the question – Why would one want to link the AccountTransaction entity with the Customer entity. Well, since we are building stock portfolio management software, it would be interesting to know the transactions (stock as well as money) for a specific customer. This naturally leads one to model this relationship as a one-to-many relationship i.e. a Customer has many (more than zero) AccountTransactions. Is this the only way this relationship can be modeled ? What if I wanted to find out the Customer information from an AccountTransaction ? Why would anyone want to do that ?

Consider the following use case : Let us say one day DalalStreet becomes quite a popular software package, and it is used by an Indian bank to handle the portfolios of its clients. Now, if a top-level manager in this bank wants to find out who were the top-10 clients who had the maximum amount (in terms of actually money traded) of transactions in the last 24 hours, how would you go about finding that information ? You would get all the AccountTransactions in the last 24 hours, and for each AccountTransaction you would find the Customer, and group all the AccountTransactions that belonged to a Customer, and then find out the top-10 Customers. The phrase that is highlighted in bold-text is possible only when you can access the Customer object from the AccountTransaction object. This can be modeled in Hibernate as a bi-directional one-to-many relationship.

So how do we go about doing this bi-directional one-to-many thing-a-majig ?

In the Customer class, you introduce a one-to-many relationship with the AccountTransaction class (see the code snippet below).

	@OneToMany (cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
	@JoinColumn (name = "customer_id")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private Set  accountTransactions;

       ...
	public void setAccountTransactions(Set  accountTransactions)
	{
		this.accountTransactions = accountTransactions;
	}
	
	public void addAccountTransaction(AccountTransaction transaction)
	{
		if (accountTransactions == null)
		{
			accountTransactions = new HashSet();
		}
		
		accountTransactions.add(transaction);
	}

	public Set  getAccountTransactions()
	{
		return accountTransactions;
	}

And in the AccountTransaction class, you model the bi-directional relationship using the following annotations.


	@ManyToOne
	@JoinColumn (name = "customer_id", updatable = false, insertable = false)
	private Customer customer;

        ....

	public Customer getCustomer()
	{
		return customer;
	}

	public void setCustomer(Customer customer)
	{
		this.customer = customer;
	}

That is all, and you are done – atleast with the annotations. There a couple of things to keep in mind, when you are actually persisting these objects into the database. Let us take a quick look at some persistence code :


		Customer customer = setupSingleCustomer();

		// save an object
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction tx = session.beginTransaction();

		Long custID = (Long) session.save(customer);

		tx.commit();
		
		MoneyTransaction mt1 = new MoneyTransaction();
		...
		MoneyTransaction mt2 = new MoneyTransaction();
		...
		StockTransaction st1 = new StockTransaction();
		...		
		StockTransaction st2 = new StockTransaction();
		...		
		StockTransaction st3 = new StockTransaction();
		...		
		// need to do this - otherwise customer id shows up as null
		customer.addAccountTransaction(mt1);
		customer.addAccountTransaction(mt2);
		customer.addAccountTransaction(st1);
		customer.addAccountTransaction(st2);
		customer.addAccountTransaction(st3);
		
		// save the account transactions - need to use the same session
		Transaction newtx = session.beginTransaction();

		Long id1 = (Long) session.save(mt1);
		Long id2 = (Long) session.save(mt2);
		Long id3 = (Long) session.save(st1);
		Long id4 = (Long) session.save(st2);
		Long id5 = (Long) session.save(st3);

		newtx.commit();
		session.close();

		System.out.println("IDs : " + id1 + ", " + id2 + ", " + id3 + ", " + id4 + ", " + id5 + ".");

		System.out.println("Customer id : " + custID);

There are two things to keep in mind when trying to persist the AccountTransaction objects :

  • One should always add the AccountTransaction object to the Customer object (lines 21-26 in the above code snippet).
  • One should always use the same session to persist the AccountTransaction object – the same session that was used to retrieve the Customer object from the database (the session object used in line 29 of the above code snippet is the same as the one created in line 04). Otherwise there will be no association in the database between the related entities. To understand the relationship between Hibernate objects and sessions, I strong encourage you to read pages 42-46 from James Elliott’s classic : “Hibernate – A Developer’s Notebook”.

Finally, here are the links to the files in case you want to take a detailed look at the code.

Handling Inheritance via Hibernate Annotations

Getting back to blogging after a long pause (I guess about a month or so) and in this post I am going to discuss how we can handle Java inheritance using Hibernate Annotations. In the process of doing this I discovered a flaw (or I guess the right word should be missing documentation) in the Hibernate documentation which is discussed below.

So I guess the first question is – why should Hibernate even bother trying to support inheritance ? Because, Hibernate is an Object Relational Mapping (ORM) tool and it is quite common to come up with a data model in which classes inherit from one another. For example, a Car and a Truck can be modelled as subclasses of a Vehicle class, a NetworkDevice and a Server can be modelled as subclasses of an ITAsset class, and in this post we discuss a model (for handling a portfolio of stocks) where a parent class – AccountTransaction – has two subclasses, MoneyTransaction and StockTransaction.

As always, all the code mentioned here is available via the Google Code Project – DalalStreet.

So this is how the object model looks like.

There are multiple ways in which such a relationship can be handled by Hibernate and I opted to use the “single table per class heirarchy” approach. This translates into the following annotations. The key annotations are the @Inheritance, @DiscriminatorColumn, and @DiscriminatorValue.

Source code for “AccountTransaction” entity :

@Entity
@Table (name="entity_transaction")
@Inheritance (strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn (name="transaction_type", discriminatorType=DiscriminatorType.STRING)
public abstract class AccountTransaction
{
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column (name = "transaction_id")
	private Long id = null;
	
	@Column (name = "transaction_type", insertable = false, updatable = false)
	private String txType = null;
	
	@Column (name = "transaction_date")
	private Date txDate = null;
	
	@Column (name = "transaction_desc")
	private String txDescription = null;
	
	@Column (name = "transaction_fee")
	private Double txFee = null;
	
	public AccountTransaction(String type)
	{
		txType = type;
		txDate = new Date();
	}
   ... 

Source code for “StockTransaction” (DiscriminatorValue is “stock”) entity :

@Entity
@DiscriminatorValue("stock")
public class StockTransaction extends AccountTransaction
{
	@Column (name = "is_sale")
	private boolean isSale = false;
	
	@Column (name = "stock_symbol")
	private String stockSymbol = null;
	
	@Column (name = "company_name")
	private String companyName = null;
	
	@Column (name = "num_shares")
	private Integer numShares = 0;
	
	@Column (name = "price_per_share")
	private Double pricePerShare = 0.0;
	
	public StockTransaction()
	{
		super("stock");
	}

   ... 

Source code for “MoneyTransaction” (DiscriminatorValue is “money”) entity :

@Entity
@DiscriminatorValue("money")
public class MoneyTransaction extends AccountTransaction
{
	@Column (name = "is_deposit")
	private boolean isDeposit = false;
	
	@Column (name = "money_amount")
	private Double moneyAmount = 0.0;
	
	public MoneyTransaction()
	{
		super("money");
	}
   ... 

Pay special attention to the annotations that describe “transaction_type” – line 11 of the AccountTransaction.java – the “insertable” and “updatable” attributes need to be set to “false”, otherwise you will get a error like this (this is the part that is missing from Hibernate documentation that I mentioned at the beginning of this post) :

Caught an exception. Error message : null
java.lang.ExceptionInInitializerError
at org.ds.biz.user.HibernateUtil.(HibernateUtil.java:17)
at org.ds.biz.user.TestInheritance.main(TestInheritance.java:60)
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: org.ds.biz.user.StockTransaction column: transaction_type (should be mapped with insert=”false” update=”false”)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:652)
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:674)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:696)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:450)
at org.hibernate.mapping.SingleTableSubclass.validate(SingleTableSubclass.java:43)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1108)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1293)
at org.ds.biz.user.HibernateUtil.(HibernateUtil.java:13)
… 1 more

The output schema from “ant schemaexport” looks something like this :

Output of ant schemaexport

Output of ant schemaexport

The values in the database looks like this :

Database rows after insert

Database rows after insert

Sample code using the Criteria API to retreive the Transaction objects (AccountTransaction, MoneyTransaction or StockTransaction) can be found in the TestInheritance class. The test class uses the different classes to retrieve the appropriate objects (see code snippet below) :


			Criteria criteria1 = session.createCriteria(AccountTransaction.class);
			List list1 = criteria1.list();			
			int size1 = list1.size();

			// should print out size as 5
			System.out.println("size of list (all transactions) : " + size1);
			...
			Criteria criteria2 = session.createCriteria(MoneyTransaction.class);			
			List list2 = criteria2.list();			
			int size2 = list2.size();
			// should print out size as 2
			System.out.println("size of list (money transactions) : " + size2);
			...
			Criteria criteria3 = session.createCriteria(StockTransaction.class);			
			List list3 = criteria3.list();			
			int size3 = list3.size();
			// should print out size as 3
			System.out.println("size of list (stock transactions) : " + size3);

Here are the links to the files in case you want to take a detailed look at the code.

Happy coding, until next time … Take care.

Hibernate One-to-One Mapping using Annotations

In an earlier post I had written about getting your development environment setup to start using Hibernate. I had talked about generating a schema, and now it makes sense to proceed to the next logical step, which is persisting data.

As usual, all the code discussed in this post is available at the Google Code Project – DalalStreet.

The objective of this post is to successfully persist a heirarchy of objects using Hibernate. The model consists of a Customer entity, this Customer entity contains an Address entity and a ContactInformation entity. The Address or ContactInformation entity cannot exist independently without a Customer – or in other words – Customer has a one-to-one relationship with Address and ContactInformation.

Hibernate documentation along with a couple of blogs (1, 2) provide insufficient information on how to model one-to-one relationships in Hibernate.

Unfortunately modeling one-to-one relationships in Hibernate is non-trivial and the correct way to model is illustrated in the following code snippets.

Source code for “Customer” entity :

@Entity
@Table(name = "entity_customer")
public class Customer
{
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column (name = "customer_id")
	private Long id = null;
	
	@Column(name = "first_name")
	private String firstName = null;
	
	@Column(name = "middle_name")
	private String middleName = null;
	
	@Column(name = "last_name")
	private String lastName = null;
	
	@Column(name = "salutation")
	private String salutation = null;
	
	@Column(name = "account_number")
	private String accountNumber = null;
	
	@OneToOne(cascade=CascadeType.ALL)
	@JoinColumn (name = "customer_id")
	private Address address = null;
	
	@OneToOne(cascade=CascadeType.ALL)
	@JoinColumn (name = "customer_id")
	private ContactInformation contactInfo = null;

Source code for “Address” entity :

@Entity
@Table(name = "entity_address")
public class Address
{
	@Column(name = "street_address1")
	private String streetAddress1 = null;

	@Column(name = "street_address2")
	private String streetAddress2 = null;

	@Column(name = "city")
	private String city = null;

	@Column(name = "state")
	private String state = null;

	@Column(name = "postal_code")
	private String postalCode = null;

	@Column(name = "country")
	private String country = null;
	
	@Id
	@GeneratedValue(generator = "foreign")
	@GenericGenerator(name = "foreign", strategy = "foreign", parameters = { @Parameter(value = "customer", name = "property") })
	@Column(name = "customer_id")
	// this is id of the customer - as an address is always associated with a
	// customer (it cannot exist independent of a customer)
	private Long customerID = null;
	
	
	@OneToOne
	@JoinColumn(name = "customer_id")
	// reference to the customer object. hibernate requires two-way object
	// references even though we are modeling a one-to-one relationship.
	private Customer customer = null;

In plain-speak this translates into the following :
Address does not have its own “ID” attribute. It will use the “ID” of the
Customer and the Customer table and the Address table are joined via this
“ID” attribute (i.e. “customer_id”).

Test code :

	private void testSingleObjectPersistence()
	{
		Customer customer = setupSingleCustomer();

		// save an object
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction tx = session.beginTransaction();

		Long custID = (Long) session.save(customer);

		tx.commit();
		session.close();

		System.out.println("Customer id : " + custID);
	}

	private Customer setupSingleCustomer()
	{
		Address address = new Address();
		address.setCity("Austin");
		address.setCountry("U.S.A");
		address.setPostalCode("78701");
		address.setState("Texas");
		address.setStreetAddress1("301 Lavaca Street");

		ContactInformation ci = new ContactInformation();
		ci.setEmailAddress("info@gingermanpub.com");
		ci.setWorkPhone("512-473-8801");

		Customer customer = new Customer();
		customer.setAccountNumber("90000200901");
		customer.setFirstName("Gingerman");
		customer.setLastName("Pub");
		customer.setMiddleName("Beer");
		customer.setSalutation("Sir");
		customer.setAddress(address);
		customer.setContactInfo(ci);

		address.setCustomer(customer);
		ci.setCustomer(customer);

		return customer;
	}

Once all the above changes have been made, Hibernate is actually able to persist the objects.

Here are the links to the files in case you want to take a detailed look at the code.

Hopefully you found this post helpful, and as always, please feel free to leave your feedback …

Your first cup of Hibernate …

Hibernate is pretty much the defacto tool/library/framework to implement Object Relational Mapping (ORM) in Java nowadays and it has definitely become a much larger project than when I first started using it in 2004. It has so many downloads (Core, Annotations, Shards, etc.) and so many jars and dependencies that it is quite difficult to decide what is required and what is not required (and what is important and what is optional).

Here I try to provide some clarity by starting with a basic Hibernate project and slowly working up (using more advanced features of Hibernate) and in the process discovering the different features of Hibernate (and their dependencies).

All the code mentioned here is available via the Google Code Project – DalalStreet.

So let us start from scratch – which means no downloads from hibernate.org, unless we absolutely need it – and proceed step by step :

  • I downloaded Eclipse 3.4.1 and created a Java Project – DalalStreet.
  • I decided to use Java annotations and Eclipse immediately gave me an error (see screenshot below)
  • Annotation Errors

    Annotation Errors

  • This can be resolved by adding ejb3-persistence.jar to the classpath of your Eclipse project. For this you need to download the hibernate annotations (I decided to use version 3.2.1 – pay special attention to the compatibility matrix) and the ejb3-persistence.jar is located in the lib folder.
  • After finishing all the annotations, you will want to export the schema, but before you can do that you need to define a hibernate config file.
  • To export the schema, I decided to use the Ant HibernateToolTask. Of course Ant didn’t know where to find this class. For this, you need to download the hibernate tools (I am using version 3.2.4), unzip it, and navigate to the plugins folder. Now navigate to the lib/tools folder inside the org.hibernate.eclipse_<version_number> folder and you will find hibernate-tools.jar (add this to the classpath of ANT).
  • After you have added the hibernate-tools.jar to the classpath you will require the following jars (to be added to the classpath of ANT)
    • hibernate3.jar from hibernate core (for obvious reasons, download hibernate core and add hibernate3.jar – found in the top level folder)
    • commons-logging-1.0.4.jar (in the above hibernate core download, lib folder)
    • hibernate-annotations.jar (in hibernate annotations download, root folder)
    • dom4j-1.6.1.jar (in hibernate core download, lib folder)
    • commons-collection-2.1.1.jar (in hibernate core download, lib folder)
    • freemarker.jar (in the hibernate tools download, inside the lib/tools folder of the org.hibernate.eclipse_<version_number> folder)
    • and finally the jdbc driver jar which is of course dependent on the database you are using (I am using the MySQL database and the following driver jar : mysql-connector-java-5.1.7-bin.jar)

    Once you have all this in place, your ANT task should complete successfully and you should have a valid schema in your database.

    A final screenshot with all the jars in your lib folder :

    Hibernate and dependent jars

    Hibernate and dependent jars

    Hope you found this post helpful. The next post will discuss the next logical step – actually persisting some data into the database using Hibernate.

Design a site like this with WordPress.com
Get started