Аннотация @OneToOne

Аннотация @OnetoOne определяет отношение один к одному — когда один объект сущности (Entity класса) включает атрибут (свойство) ссылающийся на другой объект сущности. Кроме того при отношении один к одному, значение атрибута, ссылающегося на другой объект должно быть уникально для всей коллекции.

Все отношения один к одному в Java являются однонаправленными, поскольку если исходный объект ссылается на целевой объект, нет гарантии, что целевой объект также имеет отношение к исходному объекту. Это отличается от реляционной базы данных, в которой отношения определяются с помощью внешних ключей и обратный запрос всегда существует. С целью приведения к соответствию парадигм СУБД и ООП в Java, спецификация JPA позволяет определить отношение один к одному как однонаправленное, так и двунаправленное.

Однонаправленное отношение @OneToOne (Example unidirectional @OneToOne). 

Однонаправленное отношения один к одному рассмотрим на примере двух Entity классов: Country - страны и CountryCode - коды стран по ISO 3166-1.

package info.deskbook.hibernate.mapping.annotation;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="COUNTRY")
public class Country implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name="ID_COUNTRY")
	private Long id;
	
	// полное наименование
	@Column(name="FULL_NAME", length = 100, nullable = false)
	private String fullName;
	
	// краткое наименование
	@Column(name="SHORT_NAME", length = 30, nullable = false)
	private String shortName;
	
	// дата основания государства
	@Column(name="DATE_FOUNDATION", nullable = false)
	@Temporal(value = TemporalType.DATE)
	private Date dateFoundation;
	
	// территория государства в кв.км.
	@Column(name="AREA")
	private Long area;
	
	// численность населения
	@Column(name="POPULATION")
	private Long population;
	
	// плотность населения на 1 кв. км.
	@Column(name="POPULATION_DENSITY", precision=12, scale=2, nullable = false)
	private BigDecimal populationDensity;
	
	public Country() {
	}

	/* Определение методов класса
	 * не приводится для краткости */
}
package info.deskbook.hibernate.mapping.annotation;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="COUNTRY_CODE")
public class CountryCode implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name="ID_COUNTRY_CODE")
	private Long id;
	
	@OneToOne
	@JoinColumn(name="ID_COUNTRY")
	private Country country;
	
	// ISO 3166-1 alpha-2
	@Column(name="CODE_ISO-A2", length = 2, nullable = false)
	private String codeISOa2;
	
	// ISO 3166-1 alpha-3
	@Column(name="CODE_ISO-A3", length = 3, nullable = false)
	private String codeISOa3;
	
	// ISO 3166-1 numeric
	@Column(name="CODE_ISO-N", length = 3, nullable = false)
	private String codeISOn3;
	
	public CountryCode() {
	}

	/* Определение методов класса
	 * не приводится для краткости */

}

На примере двух сущностей видно, что Entity класс Country не содержит ссылок на Entity класс CountryCode. Тогда как класс CountryCode содержит ссылку (свойство) на класс Country. Свойство [country] аннотировано @OneToOne отвечающее за связь сущностей на уровне базы данных, а также определяется имя поля для таблицы CountryCode, по которому будет создан внешний ключ определяющий отношение один к одному на уровне базы данных. Следовательно, имея внешний ключ на уровне базе данных, информацию по странам и кодам стран, можно получит с помощью SQL запросов. На уровне Java кода, объект Entity класса Country не содержит никакой информации о кодах страны по стандарту ISO 3166-1. Эту информацию можно будет получить, только после отдельных операций поиска по коду страны сущности CountryCode или реализовывать отдельный запрос по обеим Entity классам Country и CountryCode.

Двунаправленное отношение @OneToOne (Example bidirectional @OneToOne).

Двунаправленное отношения один к одному рассмотрим на примере тех-же двух Entity классов: Country - страны и CountryCode - коды стран по ISO 3166-1, внеся небольшие изменения. Entity класс CountryCode остается без изменений, соответственно код класса приводится не будет. Ниже в сокращенном варианте приведен код Entity класса Country с произведенными изменениями:

package info.deskbook.hibernate.mapping.annotation;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="COUNTRY")
public class Country implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name="ID_COUNTRY")
	private Long id;
	
	// полное наименование
	@Column(name="FULL_NAME", length = 100, nullable = false)
	private String fullName;
	
	// краткое наименование
	@Column(name="SHORT_NAME", length = 30, nullable = false)
	private String shortName;
	
	@OneToOne(fetch = FetchType.LAZY)
	private CountryCode countryCode;
	
	// Определение дополнительных свойств класса
	// не приводится для краткости
	
	public Country() {
	}

	/* Определение методов класса
	 * не приводится для краткости */
}

После внесенных изменений, при инициализации объекта Contry, будет доступна информация о кодах ISO 3166-1.

Список опций аннотации @OneToOne
опция тип значение по умолчанию описание
 cascade  CascadeType [] {}  Операции, которые должны быть каскадированы в цель ассоциации. По умолчанию никакие операции не выполняются каскадно.
 fetch FetchType   FetchType.EAGER Определяет как должны загружаться данные ассоциации: отложено или немедленно.
 mappedBy String   "" Поле, которому принадлежат отношения. Этот элемент указывается только на обратной (не принадлежащей) стороне ассоциации.
 optional  boolean  true Является ли ассоциация необязательной. Если установлено значение «ложь», должно существовать непустое отношение.
 orphanRemoval  boolean false  Следует ли применять операцию удаления к объектам, которые были удалены из отношения, и каскадировать операцию удаления для этих объектов.
 targetEntity  java.lang.Class void.class Класс сущностей, который является целью ассоциации. По умолчанию используется тип поля или свойства, которое хранит эту ассоциацию.

Смотрите также примеры JPA аннотаций при использовании Hibernate: