Learnitweb

JPA @Embedded And @Embeddable

1. Introduction

In this tutorial, we’ll discuss embeddable types in JPA.

An embeddable type is a composition of values. If you have a class which naturally is a part of another class then this class can be made embedded. For example, consider a class Address, which has properties Country, State and City. This Address class is a part of another class Employee. The Address class can be created as embeddable.

Generally embeddable types are used to group multiple basic type mappings and reuse them across several entities. The composed values are mapped to the same table as the parent table.

Following are some important points about embeddable types:

  • An embeddable type is another form of a value type.
  • An embeddable type’s lifecycle is bound to a parent entity type.
  • Embeddable types can be made up of basic values as well as associations.
  • Embeddable type when used as collection elements, cannot define collections themselves.
  • An Embeddable type shares the identity of the entity.

Following is an example of embeddable type Address.

@Entity
public class Employee {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

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

	@Embedded
	Address address;
	
	// constructor, getter and setter removed for brevity
}
@Embeddable
public class Address {
	@Column(name = "country")
	private String country;

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

	@Column(name = "city")
	private String city;
	
	// constructor, getter and setter removed for brevity
}

2. @Embeddable and @Embedded annotations

2.1 @Embeddable

This annotation specifies a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entity. In our example, @Embeddable annotation is used to specify the Address class will be used as a component. Address does not have its own primary key and shares the primary key of the enclosing Employee class. @Embeddable is used to describe the mapping type itself.

2.1 @Embedded

This annotation specifies a persistent field or property of an entity whose value is an instance of an embeddable class. The embeddable class must be annotated as @Embeddable. @Embedded is for referencing a given embeddable type.

Note that in our example, Address field in Employee is annotated with @Embedded.

3. Example

We have already mentioned an embeddable type Address earlier in this tutorial. Lets try to save an Employee instance. A typical client code looks like the following:

Session session = HibernateUtil.getSessionFactory().openSession();
transaction = session.beginTransaction();

Address address = new Address("Dummy Country", "Dummy State", "Dummy city");
Employee employee = new Employee();
employee.setName("Dummy name");
employee.setAddress(address);

session.save(employee);

transaction.commit();

Hibernate generates the following insert statement:

Hibernate: insert into Employee (city, country, state, name) values (?, ?, ?, ?)
BasicBinder:64 - binding parameter [1] as [VARCHAR] - [Dummy city]
BasicBinder:64 - binding parameter [2] as [VARCHAR] - [Dummy Country]
BasicBinder:64 - binding parameter [3] as [VARCHAR] - [Dummy State]
BasicBinder:64 - binding parameter [4] as [VARCHAR] - [Dummy name]

4. Multiple embeddable types and Overriding Embeddable types

It is possible to include the same embeddable type multiple times in the same parent entity type, but we have to set the associated column names explicitly. This is because JPA expects a database column having the same name with its associated object property.

If an embeddable type is used multiple times in some entity, you need to use the @AttributeOverride and @AssociationOverride annotations to override the default column names defined by the Embeddable.

Lets change our Employee class to include two instances of Address. We can then use @AttributeOverride annotation to specify the mapping.

@Entity
@AttributeOverrides({
		@AttributeOverride(name = "currentAddress.country", column = @Column(name = "current_address_country")),
		@AttributeOverride(name = "currentAddress.state", column = @Column(name = "current_address_state")),
		@AttributeOverride(name = "currentAddress.city", column = @Column(name = "current_address_city")),
		@AttributeOverride(name = "permanentAddress.country", column = @Column(name = "permanent_address_country")),
		@AttributeOverride(name = "permanentAddress.state", column = @Column(name = "permanent_address_state")),
		@AttributeOverride(name = "permanentAddress.city", column = @Column(name = "permanent_address_city")), })
public class Employee {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;

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

	Address currentAddress;

	Address permanentAddress;
}

Hibernate will generate the following SQL statements:

Hibernate: insert into Employee (current_address_city, current_address_country, current_address_state, name, permanent_address_city, permanent_address_country, permanent_address_state) values (?, ?, ?, ?, ?, ?, ?)
BasicBinder:64 - binding parameter [1] as [VARCHAR] - [Current city]
BasicBinder:64 - binding parameter [2] as [VARCHAR] - [Current Country]
BasicBinder:64 - binding parameter [3] as [VARCHAR] - [Current State]
BasicBinder:64 - binding parameter [4] as [VARCHAR] - [Dummy name]
BasicBinder:64 - binding parameter [5] as [VARCHAR] - [Permanent city]
BasicBinder:64 - binding parameter [6] as [VARCHAR] - [Permanent Country]
BasicBinder:64 - binding parameter [7] as [VARCHAR] - [Permanent State]