# An Overview of Identifiers in Hibernate/JPA

### 1. Overview

Identifiers in Hibernate represent the primary key of an entity. This implies the values are unique so that they can identify a specific entity, that they aren’t null and that they won’t be modified.

Hibernate provides a few different ways to define identifiers. In this article, we’ll review each method of mapping entity ids using the library.

### **2. Simple Identifiers** <a href="#bd-simple-identifiers" id="bd-simple-identifiers"></a>

The most straightforward way to define an identifier is by using the *@Id* annotation.

Simple ids are mapped using *@Id* to a single property of one of these types: Java primitive and primitive wrapper types, *String*, *Date*, *BigDecimal* and *BigInteger*.

Let’s see a quick example of defining an entity with a primary key of type *long*:

```java
@Entity
public class Student {

    @Id
    private long studentId;
    
    // standard constructor, getters, setters
}
```

### **3. Generated Identifiers** <a href="#bd-generated-identifiers" id="bd-generated-identifiers"></a>

If we want to automatically generate the primary key value, **we can add the&#x20;*****@GeneratedValue*****&#x20;annotation.**

This can use four generation types: AUTO, IDENTITY, SEQUENCE and TABLE.

If we don’t explicitly specify a value, the generation type defaults to AUTO.

#### **3.1.&#x20;*****AUTO*****&#x20;Generation** <a href="#bd-1-auto-generation" id="bd-1-auto-generation"></a>

If we’re using the default generation type, the persistence provider will determine values based on the type of the primary key attribute. This type can be numerical or *UUID*.

For numeric values, the generation is based on a sequence or table generator, while *UUID* values will use the *UUIDGenerator*.

Let’s first map an entity primary key using AUTO generation strategy:

```java
@Entity
public class Student {

    @Id
    @GeneratedValue
    private long studentId;

    // ...
}
```

In this case, the primary key values will be unique at the database level.

**Now we’ll look at the&#x20;*****UUIDGenerator*****, which was introduced in Hibernate 5.**

In order to use this feature, we just need to declare an id of type *UUID* with *@GeneratedValue* annotation:

```java
@Entity
public class Course {

    @Id
    @GeneratedValue
    private UUID courseId;

    // ...
}
```

Hibernate will generate an id of the form “8dd5f315-9788-4d00-87bb-10eed9eff566”.

#### **3.2.&#x20;*****IDENTITY*****&#x20;Generation** <a href="#bd-2-identity-generation" id="bd-2-identity-generation"></a>

This type of generation relies on the *IdentityGenerator*, which expects values generated by an *identity* column in the database. This means they are auto-incremented.

To use this generation type, we only need to set the *strategy* parameter:

```java
@Entity
public class Student {

    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private long studentId;

    // ...
}
```

One thing to note is that IDENTITY generation disables batch updates.

#### **3.3.&#x20;*****SEQUENCE*****&#x20;Generation** <a href="#bd-3-sequence-generation" id="bd-3-sequence-generation"></a>

To use a sequence-based id, Hibernate provides the *SequenceStyleGenerator* class.

This generator uses sequences if our database supports them. It switches to table generation if they aren’t supported.

In order to customize the sequence name, we can use the *@GenericGenerator* annotation with *SequenceStyleGenerator strategy*:

```java
@Entity
public class User {
    @Id
    @GeneratedValue(generator = "sequence-generator")
    @GenericGenerator(
      name = "sequence-generator",
      strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
      parameters = {
        @Parameter(name = "sequence_name", value = "user_sequence"),
        @Parameter(name = "initial_value", value = "4"),
        @Parameter(name = "increment_size", value = "1")
        }
    )
    private long userId;
    
    // ...
}
```

In this example, we’ve also set an initial value for the sequence, which means the primary key generation will start at 4.

*SEQUENCE* is the generation type recommended by the Hibernate documentation.

**The generated values are unique per sequence.** If we don’t specify a sequence name, Hibernate will reuse the same *hibernate\_sequence* for different types.

#### **3.4. TABLE Generation** <a href="#bd-4-table-generation" id="bd-4-table-generation"></a>

The *TableGenerator* uses an underlying database table that holds segments of identifier generation values.

Let’s customize the table name using the *@TableGenerator* annotation:

```java
@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, 
      generator = "table-generator")
    @TableGenerator(name = "table-generator", 
      table = "dep_ids", 
      pkColumnName = "seq_id", 
      valueColumnName = "seq_value")
    private long depId;

    // ...
}
```

In this example, we can see that we can also customize other attributes such as the *pkColumnName* and *valueColumnName*.

However, the disadvantage of this method is that it doesn’t scale well and can negatively affect performance.

**To sum up, these four generation types will result in similar values being generated but use different database mechanisms.**

#### **3.5. Custom Generator** <a href="#bd-5-custom-generator" id="bd-5-custom-generator"></a>

Let’s say we don’t want to use any of the out-of-the-box strategies. In order to do that, **we can define our custom generator by implementing the&#x20;*****IdentifierGenerator*****&#x20;interface.**

We’ll create a generator that builds identifiers containing a *String* prefix and a number:

```java
public class MyGenerator 
  implements IdentifierGenerator, Configurable {

    private String prefix;

    @Override
    public Serializable generate(
      SharedSessionContractImplementor session, Object obj) 
      throws HibernateException {

        String query = String.format("select %s from %s", 
            session.getEntityPersister(obj.getClass().getName(), obj)
              .getIdentifierPropertyName(),
            obj.getClass().getSimpleName());

        Stream ids = session.createQuery(query).stream();

        Long max = ids.map(o -> o.replace(prefix + "-", ""))
          .mapToLong(Long::parseLong)
          .max()
          .orElse(0L);

        return prefix + "-" + (max + 1);
    }

    @Override
    public void configure(Type type, Properties properties, 
      ServiceRegistry serviceRegistry) throws MappingException {
        prefix = properties.getProperty("prefix");
    }
}
```

In this example, **we override the&#x20;*****generate()*****&#x20;method from the&#x20;*****IdentifierGenerator*****&#x20;interface.**

First, we want to find the highest number from the existing primary keys of the form *prefix-XX*. Then we add 1 to the maximum number found and append the *prefix* property to get the newly generated id value.

Our class also implements the *Configurable* interface so that we can set the *prefix* property value in the *configure()* method.

Next, let’s add this custom generator to an entity.

For this, **we can use the&#x20;*****@GenericGenerator*****&#x20;annotation with a&#x20;*****strategy*****&#x20;parameter that contains the full class name of our generator class**:

```java
@Entity
public class Product {

    @Id
    @GeneratedValue(generator = "prod-generator")
    @GenericGenerator(name = "prod-generator", 
      parameters = @Parameter(name = "prefix", value = "prod"), 
      strategy = "com.baeldung.hibernate.pojo.generator.MyGenerator")
    private String prodId;

    // ...
}
```

Also, notice we’ve set the prefix parameter to “prod”.

Let’s see a quick JUnit test for a clearer understanding of the id values generated:

```java
@Test
public void whenSaveCustomGeneratedId_thenOk() {
    Product product = new Product();
    session.save(product);
    Product product2 = new Product();
    session.save(product2);

    assertThat(product2.getProdId()).isEqualTo("prod-2");
}
```

Here the first value generated using the “prod” prefix was “prod-1”, followed by “prod-2”.

### **4. Composite Identifiers** <a href="#bd-composite-identifiers" id="bd-composite-identifiers"></a>

Besides the simple identifiers we’ve seen so far, Hibernate also allows us to define composite identifiers.

A composite id is represented by a primary key class with one or more persistent attributes.

**The primary key class must fulfil several conditions**:

* It should be defined using *@EmbeddedId* or *@IdClass* annotations.
* It should be public, serializable and have a public no-arg constructor.
* Finally, it should implement *equals()* and *hashCode()* methods.

The class’s attributes can be basic, composite or ManyToOne, while avoiding collections and *OneToOne* attributes.

#### **4.1.&#x20;*****@EmbeddedId*** <a href="#bd-1-embeddedid" id="bd-1-embeddedid"></a>

Now let’s look at how to define an id using *@EmbeddedId*.

First, we need a primary key class annotated with *@Embeddable*:

```java
@Embeddable
public class OrderEntryPK implements Serializable {

    private long orderId;
    private long productId;

    // standard constructor, getters, setters
    // equals() and hashCode() 
}
```

Next, we can add an id of type *OrderEntryPK* to an entity using @*EmbeddedId*:

```java
@Entity
public class OrderEntry {

    @EmbeddedId
    private OrderEntryPK entryId;

    // ...
}
```

Let’s see how we can use this type of composite id to set the primary key for an entity:

```java
@Test
public void whenSaveCompositeIdEntity_thenOk() {
    OrderEntryPK entryPK = new OrderEntryPK();
    entryPK.setOrderId(1L);
    entryPK.setProductId(30L);
        
    OrderEntry entry = new OrderEntry();
    entry.setEntryId(entryPK);
    session.save(entry);

    assertThat(entry.getEntryId().getOrderId()).isEqualTo(1L);
}
```

Here the *OrderEntry* object has an *OrderEntryPK* primary id formed of two attributes: *orderId* and *productId*.

#### **4.2.&#x20;*****@IdClass*** <a href="#bd-2-idclass" id="bd-2-idclass"></a>

The *@IdClass* annotation is similar to the *@EmbeddedId*. The difference with *@IdClass* is that the attributes are defined in the main entity class using *@Id* for each one. The primary key class will look the same as before.

Let’s rewrite the *OrderEntry* example with an *@IdClass*:

```java
@Entity
@IdClass(OrderEntryPK.class)
public class OrderEntry {
    @Id
    private long orderId;
    @Id
    private long productId;
    
    // ...
}
```

Then we can set the id values directly on the *OrderEntry* object:

```java
@Test
public void whenSaveIdClassEntity_thenOk() {        
    OrderEntry entry = new OrderEntry();
    entry.setOrderId(1L);
    entry.setProductId(30L);
    session.save(entry);

    assertThat(entry.getOrderId()).isEqualTo(1L);
}
```

Note that for both types of composite ids, the primary key class can also contain *@ManyToOne* attributes:

```java
@Embeddable
public class OrderEntryPK implements Serializable {

    private long orderId;
    private long productId;
    @ManyToOne
    private User user;

    // ...
}
```

```java
@Entity
@IdClass(OrderEntryPK.class)
public class OrderEntryIdClass {
    @Id
    private long orderId;
    @Id
    private long productId;
    @ManyToOne
    private User user;

    // ...
}
```

Hibernate also allows defining primary keys made up of *@ManyToOne* associations combined with *@Id* annotation. In this case, the entity class should also fulfil the conditions of a primary key class.

However, the disadvantage of this method is that there’s no separation between the entity object and the identifier.

### **5. Derived Identifiers** <a href="#bd-derived-identifiers" id="bd-derived-identifiers"></a>

Derived identifiers are obtained from an entity’s association using the *@MapsId* annotation.

First, let’s create a *UserProfile* entity that derives its id from a one-to-one association with the *User* entity:

```java
@Entity
public class UserProfile {

    @Id
    private long profileId;
    
    @OneToOne
    @MapsId
    private User user;

    // ...
}
```

Next, let’s verify that a *UserProfile* instance has the same id as its associated *User* instance:

```java
@Test
public void whenSaveDerivedIdEntity_thenOk() {        
    User user = new User();
    session.save(user);
       
    UserProfile profile = new UserProfile();
    profile.setUser(user);
    session.save(profile);

    assertThat(profile.getProfileId()).isEqualTo(user.getUserId());
}
```

### **6. Conclusion** <a href="#bd-conclusion" id="bd-conclusion"></a>

In this article, we’ve seen the multiple ways we can define identifiers in Hibernate.

The full source code of the examples can be found [over on GitHub](https://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5).

{% embed url="<https://www.baeldung.com/hibernate-identifiers>" %}
