Аннотация @OneToMany

Ассоциация @OneToMany связывает родительский объект (Entity класс) с одним или несколькими дочерними объектами (Entity классами). Если @OneToMany не имеет зеркальной ассоциации @ManyToOne на дочерней стороне, ассоциация @OneToMany является однонаправленной. Если на дочерней стороне есть ассоциация @ManyToOne, ассоциация @OneToMany является двунаправленной.

Рассмотрим отношение один ко многим на примере сущностей, реализованных в предыдущем материале, описывающих страны [Country] и валюты [Currency]. Одна и та же валюта может использоваться в различных странах. Следовательно со стороны Entity класса Currency может использоваться ассоциация @OneToMeny, которая в свою очередь может быть однонаправленной или двунаправленной.

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

Для реализации однонаправленной ассоциации для классов Currency и Country создадим свойство [countrys] на стороне Entity класса Currency, представляющее собой коллекцию стран, в которых используется валюта, определенная в объекте класса Currency.

@Entity
@Table(name="CURRENCY")
public class Currency implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name="ID_CURRENCY")
	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;
	
	@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
	private List<Country> countrys = new ArrayList<>();
	
	public Currency() {
	}
	
	/* Определение методов класса
	 * не приводится для краткости */
}
@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;
	
	public Country() {
	}

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

На практике однонаправленное отношение @OneToMany не популярно. Одним из больших недостатков ассоциации является наличие дополнительной таблицы на стороне базы данных. Таблица будет содержать информацию по связанным объектам Entity классов Currency и Country.

CREATE TABLE CURRENCY (
	c BIGINT NOT NULL,
	FULL_NAME VARCHAR(100) NOT NULL,
	SHORT_NAME VARCHAR(30) NOT NULL,
    PRIMARY KEY ( ID_CURRENCY )
)

CREATE TABLE CURRENCY_COUNTRY (
    ID_CURRENCY BIGINT NOT NULL ,
    ID_COUNTRY BIGINT NOT NULL
)

CREATE TABLE COUNTRY (
    ID_COUNTRY BIGINT NOT NULL ,
	FULL_NAME VARCHAR(100) NOT NULL,
	SHORT_NAME VARCHAR(30) NOT NULL,
    PRIMARY KEY ( ID_COUNTRY )
)

ALTER TABLE CURRENCY_COUNTRY
ADD CONSTRAINT UK_CURRENCY_COUNTRY
UNIQUE (ID_COUNTRY)

ALTER TABLE CURRENCY_COUNTRY
ADD CONSTRAINT FK_CURRENCY_COUNTRY_ID_CURRENCY
FOREIGN KEY (ID_CURRENCY) REFERENCES CURRENCY

ALTER TABLE CURRENCY_COUNTRY
ADD CONSTRAINT FK_CURRENCY_COUNTRY_ID_COUNTRY
FOREIGN KEY (ID_COUNTRY) REFERENCES COUNTRY

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

Для примера двунаправленного отношения @OnetoMeny используем уже готовые классы связанные @ManyToOne из материала Аннотация @ManyToOne.

@Entity
@Table(name="CURRENCY")
public class Currency implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@Column(name="ID_CURRENCY")
	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;
	
	@OneToMany
	private List<Country> countrys = new ArrayList<>();
	
	public Currency() {
	}
	
	/* Определение методов класса
	 * не приводится для краткости */
}
@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;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ID_CURRENCY")
	private Currency currency;
	
	// Определение дополнительных свойств класса
	// не приводится для краткости
	
	public Country() {
	}

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

Для реализации двунаправленной ассоциации один-ко-многим (Entity класс Currency) необходимо иметь ассоциацию многие-к-одному на обратной стороне (Entity класс Country). Данная модель отношений со стороны Java кода наиболее соответствует парадигме отношений на стороне реляционной СУБД (DBMS):

CREATE TABLE CURRENCY (
	c BIGINT NOT NULL,
	FULL_NAME VARCHAR(100) NOT NULL,
	SHORT_NAME VARCHAR(30) NOT NULL,
    PRIMARY KEY ( ID_CURRENCY )
)

CREATE TABLE COUNTRY (
    ID_COUNTRY BIGINT NOT NULL ,
	FULL_NAME VARCHAR(100) NOT NULL,
	SHORT_NAME VARCHAR(30) NOT NULL,
	ID_CURRENCY BIGINT NOT NULL ,
    PRIMARY KEY ( ID_COUNTRY )
)

ALTER TABLE COUNTRY
ADD CONSTRAINT FK_COUNTRY_ID_CURRENCY
FOREIGN KEY (ID_CURRENCY) REFERENCES CURRENCY
Список опций аннотации @OneToMeny
опция тип значение по умолчанию описание
 cascade  CascadeType [] {}  Операции, которые должны быть каскадированы в цель ассоциации. По умолчанию никакие операции не выполняются каскадно.
 fetch FetchType   FetchType.EAGER Определяет как должны загружаться данные ассоциации: отложено или немедленно.
 mappedBy String   "" Поле, которому принадлежат отношения. Этот элемент указывается только на обратной (не принадлежащей) стороне ассоциации.
 orphanRemoval  boolean false  Следует ли применять операцию удаления к объектам, которые были удалены из отношения, и каскадировать операцию удаления для этих объектов.
 targetEntity  java.lang.Class void.class Класс сущностей, который является целью ассоциации. По умолчанию используется тип поля или свойства, которое хранит эту ассоциацию.


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