Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Hibernate

You're reading from   Mastering Hibernate Learn how to correctly utilize the most popular Object-Relational Mapping tool for your Enterprise application

Arrow left icon
Product type Paperback
Published in May 2016
Publisher Packt
ISBN-13 9781782175339
Length 204 pages
Edition 1st Edition
Languages
Arrow right icon
Toc

Entity

A Hibernate entity is, typically, a sophisticated Plain Old Java Object (POJO). It is sophisticated because it represents a business model whose data is assumed to be persistent. It's always decorated with various annotations, which enable additional characteristics, among other things. Or, it is configured using an hbm Hibernate mapping XML file. When an entity contains other entities, or a collection of other entities, this implies a database association for which you have to declare the proper mapping configuration to define the relationship type.

An entity can also embed other POJOs that are not entities. In such cases, the other entities are considered value objects. They have no identity, and have little business significance on their own. (We will discuss this further when we talk about the @Embedded and @Embeddable annotations in Chapter 2, Advanced Mapping).

Entity lifecycle

You should already be familiar with entity lifecycle. However, here is a different perspective of the different phases of the lifecycle.

Before discussing the lifecycle of an entity, it is important to not think of an entity as a POJO. Instead, if you keep reminding yourself that an entity is the persistent model of business data, you will easily understand the lifecycle.

The lifecycle begins when you instantiate an entity class. At this point, the entity has no presence in the persistence context; therefore, no data has been inserted in the database and no unique ID is assigned to the new entity. At this phase of the lifecycle, the entity is said to be in the Transient state.

Once you save your new entity by calling session.save(), your entity is now in the Persistent state, because at this point the session is managing it.

What happens to the entities after the session is closed? In this case, your entity has no presence in the persistence context, but it has a presence in the database. This state is called Detached.

There is another state, which is rarely mentioned, and this is the Deleted state. When you call session.delete() on an entity, it will fire off a Delete event and internally sets the entity state to DELETED. As long as the session is open, you can still undelete the entity by calling session.persist().

There are certain lifecycle events that change the entity state, and those are well documented.

Types of entities

As mentioned earlier, you can declare a POJO class as your persistent class. There is another type of entity in Hibernate that is rarely used and perhaps not widely known, and this is map. This is known as a dynamic entity. You can use any implementation of the java.util.Map interface as a Hibernate entity. This is useful to implement a dynamic business model, which is great for the creation of a quick prototype. Ultimately, you are best off with POJO entities. If you need to implement a dynamic entity, first you can set the default entity mode to MAP:

Configuration configuration = new Configuration()
.configure()
.setProperty(Environment.DEFAULT_ENTITY_MODE,
EntityMode.MAP.toString());

Then, add a new mapping configuration. Hibernate uses the property name as a map key to get the value, for example, <property name="firstname" …/>. So, if your map contains other properties which are not included in the named map, they will be ignored by Hibernate:

<hibernate-mapping>
  <class entity-name="DynamicEntity">
    <id name="id" type="long" column="MAP_ID">
      <generator class="sequence" />
    </id>
    <property name="firstname" type="string" column="FIRSTNAME" />
    <property name="lastname" type="string" column="LASTNAME" />
  </class>
</hibernate-mapping>

Make sure that you add the new map to your Hibernate configuration. Now, you can use this as an entity. Note that when you call session.save(), you are passing the name of the entity as the first argument:

    Map<String, String> myMap = new HashMap<String, String>();
    myMap.put("firstname", "John");
    myMap.put("lastname", "Smith");
    
    Session session = HibernateUtil
   .getSessionFactory()
   .getCurrentSession();
    Transaction transaction = session.beginTransaction();

    try {
      session.save("DynamicEntity", myMap); // notice entity name
      transaction.commit();
    }
   catch (Exception e) {
      transaction.rollback();	
      // log error
    }
    finally {
      if (session.isOpen())
        session.close();
    }

Note

This used to be different in version 3.6. You didn't need to set the default entity mode on the configuration. The Session interface provided an API, which would return another session that supported dynamic entity. This was session.getSession(EntityMode.MAP), and this returned a new session, which inherited the JDBC connection and the transaction. However, this was removed in Hibernate 4.

Identity crisis

Each entity class has a property that is marked as the unique identifier of that entity. This could be a primitive data type or another Java class, which would represent a composite ID. (You'll see this in Chapter 2, Advanced Mapping, when we talk about mapping) For now, having an ID is still optional, but in future releases of Hibernate, this will no longer be the case and every entity class must have an ID attribute.

Furthermore, as Hibernate is responsible for generating and setting the ID, you should always protect it by making sure that the setter method for the ID is private so that you don't accidentally set the ID in your code. Hibernate can access private fields using reflection. Hibernate also requires entities to have a no-arg constructor.

In some cases, you have to override the equals() and hashCode() methods, especially if you are keeping the detached objects around and want to reattach them or need to add them to a set. This is because outside of the persistence context the Java equality may fail even though you are comparing two entity instances that represent the same row. The default implementation of the equals() method only checks whether the two instances are the same reference.

If you are sure that both objects have an ID assigned, then, in addition to reference equality check, you can compare their identifiers for equality. If you can't rely on the ID property but an entity can be uniquely identified by a business key, such as user ID or social security number, then you can compare the business keys.

It's not a good idea to compare all properties for equality check. There are several reasons, as follows:

  • First, if you keep a detached object around and then retrieve it again in another session, Hibernate can't tell that they are the same entities if you modify one of them.
  • Second, you may have a long list of properties and your code will look messy, and if you add a new property, you may forget to modify the equals() method.
  • Finally, this approach will lead to equal entities if you have multiple database rows with the same values, and they should be treated as different entities because they represent different rows. (For example, if two people live at the same address and one person moves, you may accidentally change the address for both.)

Beyond JPA

When you decorate your class with annotations, you are empowering your objects with additional features. There are certain features that are provided by Hibernate, which are not available in JPA.

Most of these features are provided through Hibernate annotations, which are packaged separately. Some annotations affect the behavior of your entity, and some are there to make mapping easier and more powerful.

The behavior modifying annotations that are worth noting here are as follows:

  • @Immutable: This makes an entity immutable.
  • @SelectBeforeUpdate: This is great for reducing unnecessary updates to the database and reducing contention. However, it does make an extra call through JDBC.
  • @BatchSize: This can be used to limit the size of a collection on fetch.
  • @DynamicInsert and @DynamicUpdat: These prevent null properties from being included in the dynamic SQL generation for both insert and update.
  • @OptimisticLocking: This is used to define the type of optimistic lock.
  • @Fetch: This can be used to define @FetchMode. You can instruct Hibernate to use Join, Select, or Sub Select. The Join query uses outer join to load the related entities, the Select query issues individual SQL select statements, and Sub Select is self-explanatory. (This is different from JPA's @FetchType, which is used to decide to perform lazy fetch or not.)
  • @Filter: This is used to limit the entities that are returned.

It's worth exploring both the org.hibernate.annotations JavaDocs and the JPA annotations. We will cover Hibernate annotations (beyond JPA) that modify mappings and associations in the next chapter, when we discuss mappings. We will also return to @Fetch and @Filter when we discuss Fetching in Chapter 4, Advanced Fetching.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image