В чем разница между @JoinColumn и mappedBy при использовании ассоциации JPA @OneToMany
в чем разница между:
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
private List<Branch> branches;
...
}
и
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
private List<Branch> branches;
...
}
5 ответов
аннотации @JoinColumn
указывает, что этот объект является владелец отношения (то есть: соответствующая таблица имеет столбец с внешним ключом к таблице, на которую ссылаются), а атрибут mappedBy
указывает, что сущность на этой стороне является обратной связью, а владелец находится в" другой " сущности. Это также означает, что вы можете получить доступ к другой таблице из класса, который вы аннотировали с помощью " mappedBy "(полностью двунаправленный отношение.)
в частности, для кода в вопросе правильные аннотации будут выглядеть так:
@Entity
public class Company {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
private List<Branch> branches;
}
@Entity
public class Branch {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "companyId")
private Company company;
}
@JoinColumn
может использоваться с обеих сторон отношений. вопрос был об использовании @JoinColumn
на @OneToMany
стороны (редкий случай). И дело здесь в физическое дублирование информации (имя столбца) вместе с не оптимизирован SQL-запрос, который будет производить некоторые дополнительные операторы обновления.
по данным документация:
С "многие к одному" являются (почти) всегда собственником части двунаправленного отношения в спецификации JPA, один ко многим ассоциации аннотируется @OneToMany (mappedBy=...)
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
войско имеет двунаправленное одно ко многим отношениям с солдатом через свойство войск. Вам не нужно (не должно) определять какое-либо физическое отображение на стороне mappedBy.
чтобы сопоставить двунаправленный один со многими, с one-to-many сторона как владеющая сторона, вы должны удалить mappedBy элемент и установите для многих значение один @JoinColumn как вставляемое и обновляемое значение false. Это решение не оптимизировано и создаст некоторые дополнительные инструкции UPDATE.
@Entity
public class Troop {
@OneToMany
@JoinColumn(name="troop_fk") //we need to duplicate the physical information
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk", insertable=false, updatable=false)
public Troop getTroop() {
...
}
аннотации mappedBy в идеале всегда следует использовать родительскую сторону (класс компании) двунаправленного отношения, в этом случае он должен быть в классе компании, указывающем на переменную-член "компания" дочернего класса (Класс филиала)
аннотации @JoinColumn используется для указания сопоставленного столбца для присоединения к ассоциации сущностей, эта аннотация может использоваться в любом классе (Родительском или дочернем), но в идеале она должна использоваться только в одна сторона (либо в родительском классе, либо в дочернем классе не в обоих) здесь, в этом случае я использовал ее в дочерней стороне (класс ветви) двунаправленного отношения, указывающего внешний ключ в классе ветви.
ниже приведен рабочий пример :
родительский класс , общество
@Entity
public class Company {
private int companyId;
private String companyName;
private List<Branch> branches;
@Id
@GeneratedValue
@Column(name="COMPANY_ID")
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
@Column(name="COMPANY_NAME")
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
@OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}
дочерний класс, филиал
@Entity
public class Branch {
private int branchId;
private String branchName;
private Company company;
@Id
@GeneratedValue
@Column(name="BRANCH_ID")
public int getBranchId() {
return branchId;
}
public void setBranchId(int branchId) {
this.branchId = branchId;
}
@Column(name="BRANCH_NAME")
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="COMPANY_ID")
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
Я просто хотел бы добавить, что @JoinColumn
не всегда должен быть связан с данные о физическом местоположении as этой ответ напрашивается. Вы можете объединить @JoinColumn
с @OneToMany
даже если в родительской таблице нет данных таблицы, указывающих на дочернюю таблицу.
как определить однонаправленное отношение OneToMany в JPA
Однонаправленное OneToMany, Отсутствие Обратного ManyToOne, Отсутствие Соединения Таблица
вроде бы только в JPA 2.x+
хотя. Это полезно для ситуаций, когда вы хотите, чтобы дочерний класс просто содержал идентификатор родителя, а не полную ссылку.
как я объяснил в в этой статье, если вы используете @OneToMany
аннотации @JoinColumn
, тогда у вас есть однонаправленная ассоциация.
если вы используете @OneToMany
с mappedBy
набор атрибутов, у вас есть двунаправленная Ассоциация, то есть вам нужно иметь @ManyToOne
ассоциация на стороне ребенка, которая mappedBy
ссылки.
The однонаправленный @OneToMany
ассоциация работает не очень хорошо, так что вы должны избегать он.
вам лучше использовать двунаправленный @OneToMany
что более эффективно.