В чем разница между @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 399

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 что более эффективно.