В чем разница между @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 стороне.
чтобы отобразить двунаправленный один для многих, с один-ко-многим сторона как владеющая сторона, вы должны удалить mappedBy элемент и установите многие в один @JoinColumn как вставляемый и обновляемый в false. Это решение не оптимизировано и создаст некоторые дополнительные инструкции обновления.
@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
не всегда должны быть связаны с данные о физическом местоположении как этой ответ напрашивается. Вы можете комбинировать@JoinColumn
с@OneToMany
даже если в родительской таблице нет табличных данных, указывающих на дочернюю таблицу.как определить однонаправленные отношения OneToMany в JPA
Однонаправленное OneToMany, Отсутствие Обратного ManyToOne, Отсутствие Соединения Таблица
он, кажется, доступен только в
JPA 2.x+
хотя. Это полезно для ситуаций, когда вы хотите, чтобы дочерний класс просто содержал идентификатор родителя, а не полную ссылку.
как я объяснил в в этой статье, если вы используете
@OneToMany
аннотации@JoinColumn
, то у вас есть однонаправленная ассоциация.если вы используете
@OneToMany
сmappedBy
набор атрибутов, у вас есть двунаправленная Ассоциация, то есть вам нужно иметь@ManyToOne
ассоциация на стороне ребенка, котораяmappedBy
ссылки.The однонаправленный
@OneToMany
ассоциация работает не очень хорошо, так что вы должны избегать оно.вам лучше использовать двунаправленный
@OneToMany
что более эффективно.