В чем разница между @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 что более эффективно.