Ai đó có thể giải thích mappedBy trong JPA và Hibernate không?


174

Tôi chưa quen với ngủ đông và cần sử dụng các mối quan hệ một-nhiều và nhiều-một. Đó là một mối quan hệ hai chiều trong các đối tượng của tôi, để tôi có thể đi qua từ một trong hai hướng. mappedBylà cách được đề xuất để đi về nó, tuy nhiên, tôi không thể hiểu nó. Ai đó có thể giải thích:

  • cách được đề nghị để sử dụng nó là gì?
  • nó giải quyết mục đích gì?

Vì lợi ích của ví dụ của tôi, đây là các lớp học của tôi với các chú thích:

  • Airline SỞ HỮU nhiều AirlineFlights
  • Nhiều người AirlineFlights thuộc về MỘT Airline

Hãng hàng không :

@Entity 
@Table(name="Airline")
public class Airline {
    private Integer idAirline;
    private String name;

    private String code;

    private String aliasName;
    private Set<AirlineFlight> airlineFlights = new HashSet<AirlineFlight>(0);

    public Airline(){}

    public Airline(String name, String code, String aliasName, Set<AirlineFlight> flights) {
        setName(name);
        setCode(code);
        setAliasName(aliasName);
        setAirlineFlights(flights);
    }

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="IDAIRLINE", nullable=false)
    public Integer getIdAirline() {
        return idAirline;
    }

    private void setIdAirline(Integer idAirline) {
        this.idAirline = idAirline;
    }

    @Column(name="NAME", nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = DAOUtil.convertToDBString(name);
    }

    @Column(name="CODE", nullable=false, length=3)
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = DAOUtil.convertToDBString(code);
    }

    @Column(name="ALIAS", nullable=true)
    public String getAliasName() {
        return aliasName;
    }
    public void setAliasName(String aliasName) {
        if(aliasName != null)
            this.aliasName = DAOUtil.convertToDBString(aliasName);
    }

    @OneToMany(fetch=FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name="IDAIRLINE")
    public Set<AirlineFlight> getAirlineFlights() {
        return airlineFlights;
    }

    public void setAirlineFlights(Set<AirlineFlight> flights) {
        this.airlineFlights = flights;
    }
}

Đèn hàng không:

@Entity
@Table(name="AirlineFlight")
public class AirlineFlight {
    private Integer idAirlineFlight;
    private Airline airline;
    private String flightNumber;

    public AirlineFlight(){}

    public AirlineFlight(Airline airline, String flightNumber) {
        setAirline(airline);
        setFlightNumber(flightNumber);
    }

    @Id
    @GeneratedValue(generator="identity")
    @GenericGenerator(name="identity", strategy="identity")
    @Column(name="IDAIRLINEFLIGHT", nullable=false)
    public Integer getIdAirlineFlight() {
        return idAirlineFlight;
    }
    private void setIdAirlineFlight(Integer idAirlineFlight) {
        this.idAirlineFlight = idAirlineFlight;
    }

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="IDAIRLINE", nullable=false)
    public Airline getAirline() {
        return airline;
    }
    public void setAirline(Airline airline) {
        this.airline = airline;
    }

    @Column(name="FLIGHTNUMBER", nullable=false)
    public String getFlightNumber() {
        return flightNumber;
    }
    public void setFlightNumber(String flightNumber) {
        this.flightNumber = DAOUtil.convertToDBString(flightNumber);
    }
}

BIÊN TẬP:

Lược đồ cơ sở dữ liệu:

AirlineFlight có idAirline là ForeignKey và Airline không có idAirlineFlight. Điều này làm cho, AirlineFlight là chủ sở hữu / thực thể xác định?

Về mặt lý thuyết, tôi muốn hãng hàng không trở thành chủ sở hữu của hãng hàng không.

nhập mô tả hình ảnh ở đây

Câu trả lời:


150

Bằng cách chỉ định @JoinColumntrên cả hai mô hình, bạn không có mối quan hệ hai chiều. Bạn có hai mối quan hệ một chiều, và một bản đồ rất khó hiểu về nó. Bạn đang nói với cả hai mô hình rằng họ "sở hữu" cột IDAIRLINE. Thực sự chỉ có một trong số họ thực sự nên! Điều 'bình thường' là loại @JoinColumnbỏ @OneToManyhoàn toàn bên cạnh, và thay vào đó thêm mappedBy vào @OneToMany.

@OneToMany(cascade = CascadeType.ALL, mappedBy="airline")
public Set<AirlineFlight> getAirlineFlights() {
    return airlineFlights;
}

Điều đó nói với Hibernate "Hãy xem qua thuộc tính bean có tên là 'hãng hàng không' về thứ tôi có một bộ sưu tập để tìm cấu hình."


1
Tôi hơi bối rối bởi mô tả của bạn cuối cùng về mappedBy. Có vấn đề như thế nào mọi thứ được tổ chức trong db? @DB: AirlineFlight có idAirline là Khóa ngoài. Hãng hàng không chỉ có idAirline làm khóa chính và không lưu thông tin về AirlineFlight @ DB.
brainydexter 2/212

10
Vâng, nó quan trọng. Tên trong mappedBy đang nói với Hibernate nơi tìm cấu hình cho JoinColumn. (Trên phương pháp getAirline () của AirlineFlight.) Cách bạn ánh xạ nó đặt JoinColumn trên máy bay, bạn đang nói với hãng hàng không mà nó trách nhiệm duy trì các giá trị trên trong bảng khác. Có thể nói với một Thực thể rằng nó "sở hữu" một cột trong một bảng khác và chịu trách nhiệm cập nhật nó. Đây không phải là điều bạn thường muốn làm và có thể gây ra sự cố với các câu lệnh SQL được thực thi.
Affe

Xin vui lòng xem chỉnh sửa. Ở cấp độ DB, bảng AirlinesFlight sở hữu idAirline dưới dạng cột khóa ngoại. Do đó, JoinColumn nên được đưa vào lớp / bảng của hãng hàng không trong ManytoOne tương ứng, vì nó sở hữu cột đó?
brainydexter 2/212

Vâng, tôi khuyên bạn nên làm theo cách đó. Đây là tùy chọn ít phức tạp nhất và bạn dường như không cần bất cứ điều gì khác.
Affe

"hoàn toàn loại bỏ @JoinColumn khỏi phía @OneToMany", ý của bạn là gì @ManyToOne, phải không?
nbro

284

MappedBy báo hiệu ngủ đông rằng chìa khóa cho mối quan hệ nằm ở phía bên kia.

Điều này có nghĩa là mặc dù bạn liên kết 2 bảng với nhau, nhưng chỉ 1 trong số các bảng đó có ràng buộc khóa ngoài với bảng kia. MappedBy cho phép bạn vẫn liên kết từ bảng không chứa ràng buộc với bảng khác.


3
bạn có thể vui lòng làm rõ hơn một chút?
Alexander Suraphel

1
@Kurt Du Bois, tại sao bạn sẽ sử dụng mappedBythay vì xác định hai hướng (với các ràng buộc nước ngoài ở mỗi bên)?
Kevin Meredith

6
Bởi vì đôi khi nó không có ý nghĩa để đặt một phím ở cả hai bên. Nói ví dụ bạn có một công ty và một chiếc di động. Một chiếc di động sẽ chỉ thuộc về một công ty, nhưng một công ty sẽ có nhiều thiết bị di động.
Kurt Du Bois

Xin lỗi anh chàng chỉnh sửa vì đã trả lại câu trả lời của tôi, nhưng thực sự không có giá trị gia tăng nào trong bản chỉnh sửa của bạn. Câu cuối cùng thậm chí không có ý nghĩa.
Kurt Du Bois

@KurtDuBois được ánh xạ bằng cách chỉ vào hình ảnh làm thế nào để tạo cơ sở dữ liệu của bạn, tức là bạn sử dụng mappedby hoặc không ngủ đông ở phía java hoạt động theo cách tương tự. Có phải vậy không?

22

mappedbynói cho chính nó, nó nói với ngủ đông không ánh xạ lĩnh vực này. nó đã được ánh xạ bởi trường này [name = "field"].
trường nằm trong thực thể khác (name of the variable in the class not the table in the database)..

Nếu bạn không làm điều đó, ngủ đông sẽ ánh xạ hai mối quan hệ này vì nó không cùng quan hệ

vì vậy chúng ta cần bảo ngủ đông chỉ thực hiện ánh xạ ở một bên và phối hợp giữa chúng.


mappedBy là tùy chọn? Bởi vì không sử dụng mappedBy tôi sẽ nhận được kết quả tương tự, tức là ánh xạ đối tượng hai chiều
Freelancer

bạn không thể sử dụng on2many và many2one mà không sử dụng mappedBy trong một trong những điều tương tự đối với nhiều người, bạn phải sử dụng mappedBy ở một bên
Charif DZ

Cảm ơn đã chỉ ra giá trị thuộc tính có nghĩa là tên của trường trong bảng khác.
Gab 5/12/2016

2
Có thể ngủ đông không phải lúc nào cũng tự nói, nhưng khi thực hiện, ít nhất thì nó cũng sử dụng dấu câu
Amalgovinus

1
Đối với tôi, nó không nói cho chính nó; ngược lại, nó rất khó hiểu. Chỉ cần nhìn vào số lượng câu hỏi liên quan đến những gì thực sự là mappedByinversedBy. Các ORM khác sử dụng các thuộc tính belongsToMany, thông minh hơn nhiều hasMany.
Tháng 1 Bodnar

12

mappedby = "đối tượng của thực thể cùng lớp được tạo trong một lớp khác

Lưu ý: -Maps by chỉ có thể được sử dụng trong một lớp vì một bảng phải chứa ràng buộc khóa ngoài. nếu ánh xạ bởi có thể được áp dụng ở cả hai phía thì nó loại bỏ khóa ngoại khỏi cả hai bảng và không có khóa ngoại thì không có mối quan hệ b / w hai bảng.

Lưu ý: - nó có thể được sử dụng cho các chú thích sau: - 1. @ OneTone 2. @ OneToMany 3. @ ManyToMany

Lưu ý --- Không thể sử dụng cho chú thích sau: - 1. @ ManyToOne

Trong một đến một: - Thực hiện ở bất kỳ phía nào của ánh xạ nhưng chỉ thực hiện ở một bên. Nó sẽ loại bỏ cột bổ sung của ràng buộc khóa ngoài trên bảng mà nó được áp dụng.

Ví dụ. Nếu chúng ta áp dụng ánh xạ trong lớp Nhân viên vào đối tượng nhân viên thì khóa ngoại từ bảng Nhân viên sẽ bị xóa.


12

Mối quan hệ bảng so với mối quan hệ thực thể

Trong một hệ thống cơ sở dữ liệu quan hệ, một one-to-manymối quan hệ bảng trông như sau:

Mối quan hệ bảng <code> một-nhiều </ code>

Lưu ý rằng mối quan hệ dựa trên cột Khóa ngoài (ví dụ post_id:) trong bảng con.

Vì vậy, có một nguồn sự thật duy nhất khi nói đến việc quản lý one-to-manymối quan hệ bảng.

Bây giờ, nếu bạn có một mối quan hệ thực thể hai chiều ánh xạ trên one-to-manymối quan hệ bảng mà chúng ta đã thấy trước đây:

Hiệp hội thực thể <code> một-nhiều </ code> hai chiều

Nếu bạn nhìn vào sơ đồ trên, bạn có thể thấy rằng có hai cách để quản lý mối quan hệ này.

Trong Postthực thể, bạn có commentsbộ sưu tập:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

Và, trong PostComment, posthiệp hội được ánh xạ như sau:

@ManyToOne(
    fetch = FetchType.LAZY
)
@JoinColumn(name = "post_id")
private Post post;

Vì có hai cách để biểu diễn cột Khóa ngoài, bạn phải xác định đâu là nguồn gốc của sự thật khi chuyển đổi trạng thái kết hợp thành sửa đổi giá trị cột Ngoại khóa tương đương.

MappedBy

Các mappedBythuộc tính nói rằng @ManyToOnebên chịu trách nhiệm quản lý các cột Ngoại Key, và bộ sưu tập chỉ được sử dụng để lấy các đối tượng trẻ em và để thác thay đổi trạng thái thực thể cha mẹ cho trẻ em (ví dụ, loại bỏ phụ huynh cũng nên loại bỏ các đối tượng trẻ em).

Đồng bộ hóa cả hai mặt của hiệp hội hai chiều

Bây giờ, ngay cả khi bạn đã xác định mappedBythuộc tính và @ManyToOneliên kết phía con quản lý cột Khóa ngoài, bạn vẫn cần đồng bộ hóa cả hai mặt của liên kết hai chiều.

Cách tốt nhất để làm điều đó là thêm hai phương thức tiện ích sau:

public void addComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

public void removeComment(PostComment comment) {
    comments.remove(comment);
    comment.setPost(null);
}

Các phương pháp addCommentremoveCommentđảm bảo rằng cả hai bên được đồng bộ hóa. Vì vậy, nếu chúng ta thêm một thực thể con, thực thể con cần trỏ đến cha mẹ và thực thể cha mẹ nên có con trong bộ sưu tập con.

Để biết thêm chi tiết về cách tốt nhất để đồng bộ hóa tất cả các loại kết hợp thực thể hai chiều, hãy xem bài viết này .


0

Bạn đã bắt đầu với ánh xạ ManyToOne, sau đó bạn đặt ánh xạ OneToMany cũng theo cách BiDirectional. Sau đó, ở phía OneToMany (thường là bảng / lớp cha mẹ của bạn), bạn phải đề cập đến "mappedBy" (ánh xạ được thực hiện bởi và trong bảng / lớp con), do đó, hibernate sẽ không tạo bảng ánh xạ EXTRA trong DB (như TableName = Parent_child).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.