Подтвердить что ты не робот

Какая разница между @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;
    ...
}
4b9b3361

Ответ 1

@JoinColumn можно использовать с обеих сторон отношения. Вопрос заключался в использовании @JoinColumn на стороне @OneToMany (редкий случай). И здесь речь идет о дублировании физической информации (имя столбца) наряду с не оптимизированным SQL-запросом, который будет создавать некоторые дополнительные инструкции UPDATE.

Согласно документации:

Так как многие к одному (почти) всегда сторона владельца двунаправленных отношений в спецификации 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 как вставляемый и обновляемый к ложному. Это решение не оптимизировано и создаст некоторые дополнительные инструкции 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() {
    ...
}

Ответ 2

Аннотация @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;
}

Ответ 3

Как я объяснил в этой статье, если вы используете @OneToMany аннотацию с @JoinColumn, то есть однонаправленные ассоциации.

Если вы используете @OneToMany с mappedBy атрибутом mappedBy, у вас есть двунаправленная связь, то есть вам нужно иметь ассоциацию @ManyToOne на дочерней стороне, на которую mappedBy ссылка.

Однонаправленная ассоциация @OneToMany работает не очень хорошо, поэтому ее следует избегать.

Вам лучше использовать двунаправленную @OneToMany которая более эффективна.

Ответ 4

В идеале всегда должна использоваться аннотация mappedBy в родительской части (класс компании) двунаправленной связи, в этом случае она должна быть в классе Company, указывая на переменную-член "компания" класс Child (класс Branch)

Аннотация @JoinColumn используется для указания сопоставленного столбца для объединения сущности, эта аннотация может использоваться в любом классе (родительском или дочернем), но в идеале его следует использовать только с одной стороны (либо в родительском классе, либо в классе Child не в обоих) здесь в этом случае я использовал его в дочерней стороне (класс Branch) двунаправленного отношения, указывающего внешний ключ в классе Branch.

ниже приведен рабочий пример:

родительский класс, компания

@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;
    }


}

Ответ 5

Я просто хотел бы добавить, что @JoinColumn не всегда должен быть связан с физическим расположением информации, как предполагает этот ответ. Вы можете комбинировать @JoinColumn с @OneToMany даже если в родительской таблице нет табличных данных, указывающих на @OneToMany таблицу.

Как определить однонаправленное отношение OneToMany в JPA

Однонаправленный OneToMany, нет обратного ManyToOne, нет таблицы соединения

Похоже, он доступен только в JPA 2.x+. Это полезно для ситуаций, когда вы хотите, чтобы дочерний класс просто содержал идентификатор родителя, а не полную ссылку на него.

Ответ 6

Я не согласен с принятым здесь ответом Оскара Лопеса. Этот ответ неточный!

Это НЕ @JoinColumn который указывает, что эта сущность является владельцем отношения. Вместо этого это аннотация @ManyToOne которая делает это (в его примере).

Аннотации отношений, такие как @ManyToOne, @OneToMany и @ManyToMany сообщают JPA/Hibernate о создании сопоставления. По умолчанию это делается через отдельную таблицу соединений.


@JoinColumn

Цель @JoinColumn - создать столбец соединения, если он еще не существует. Если это так, то эту аннотацию можно использовать для именования столбца соединения.


MappedBy

Назначение параметра MappedBy состоит в том, чтобы MappedBy JPA: НЕ создавайте другую таблицу соединения, поскольку отношение уже сопоставляется противоположным объектом этого отношения.



Помните: MappedBy - это свойство аннотаций отношений, целью которого является создание механизма для связи двух сущностей, что по умолчанию они делают, создавая объединяющую таблицу. MappedBy останавливает этот процесс в одном направлении.

MappedBy, что сущность, не использующая MappedBy является владельцем отношения, потому что механизм сопоставления определяется внутри его класса посредством использования одной из трех аннотаций сопоставления для поля внешнего ключа. Это не только определяет характер сопоставления, но и дает указание создать таблицу соединений. Кроме того, опция подавления таблицы соединения также существует путем применения аннотации @JoinColumn к внешнему ключу, которая вместо этого хранит ее в таблице объекта-владельца.

Итак, в итоге: @JoinColumn либо создает новый столбец соединения, либо переименовывает существующий; в то время MappedBy параметр MappedBy работает совместно с аннотациями отношений другого (дочернего) класса, чтобы создать отображение либо через таблицу соединения, либо путем создания столбца внешнего ключа в связанной таблице объекта-владельца.

Чтобы проиллюстрировать, как работает MapppedBy, рассмотрим код ниже. Если MappedBy параметр MappedBy был удален, то Hibernate фактически создал бы ДВЕ таблицы соединения! Зачем? Потому что во взаимоотношениях "многие ко многим" существует симметрия, а в Hibernate нет смысла выбирать одно направление над другим.

Поэтому мы используем MappedBy чтобы сообщить Hibernate, что мы выбрали другую сущность, чтобы диктовать отображение отношений между двумя сущностями.

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    private List<Drivers> drivers;
}

Добавление @JoinColumn (name = "driverID") в класс владельца (см. Ниже) предотвратит создание таблицы соединения и вместо этого создаст столбец внешнего ключа driverID в таблице Cars для построения сопоставления:

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    @JoinColumn(name = "driverID")
    private List<Drivers> drivers;
}

Ответ 7

JPA - это многоуровневый API, различные уровни имеют свои собственные аннотации. Самый высокий уровень - это (1) уровень сущности, который описывает постоянные классы, тогда у вас есть (2) уровень реляционной базы данных, который предполагает, что сущности отображаются в реляционную базу данных, и (3) модель Java.

Примечания уровня 1: @Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany. Вы можете внести постоянство в свое приложение, используя только эти высокоуровневые аннотации. Но тогда вы должны создать свою базу данных в соответствии с предположениями, которые делает JPA. Эти аннотации определяют модель сущности/отношения.

Аннотации уровня 2: @Table, @Column, @JoinColumn,... Влиять на сопоставление сущностей/свойств с таблицами/столбцами реляционной базы данных, если вас не устраивают значения по умолчанию JPA или если вам необходимо сопоставить существующую базу данных. Эти аннотации можно рассматривать как аннотации реализации, они определяют, как должно выполняться отображение.

По моему мнению, лучше всего придерживаться аннотаций высокого уровня, а затем вводить аннотации более низкого уровня по мере необходимости.

Чтобы ответить на вопросы: @OneToMany/mappedBy хорош, потому что он использует только аннотации из домена объекта. @OneToMany/@JoinColumn также хорош, но он использует аннотацию реализации, где это не является строго необходимым.