Bisakah seseorang menjelaskan dipetakan oleh JPA dan Hibernate?

174

Saya baru hibernasi dan perlu menggunakan hubungan satu-ke-banyak dan banyak-ke-satu. Itu adalah hubungan dua arah dalam benda-benda saya, sehingga saya dapat melintasi dari kedua arah. mappedByadalah cara yang disarankan untuk menyelesaikannya, namun, saya tidak bisa memahaminya. Dapatkah seseorang menjelaskan:

  • apa cara yang disarankan untuk menggunakannya?
  • apa tujuannya?

Demi contoh saya, berikut adalah kelas-kelas saya dengan anotasi:

  • Airline SENDIRI banyak AirlineFlights
  • Banyak AirlineFlights milik ONE Airline

Maskapai Penerbangan :

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

AirlineFlight:

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

EDIT:

Skema basis data:

AirlineFlights memiliki idAirline sebagai ForeignKey dan Airline tidak memiliki idAirlineFlight. Ini menjadikan, AirlineFlight sebagai pemilik / entitas yang mengidentifikasi?

Secara teoritis, saya ingin maskapai menjadi pemilik airlineFlight.

masukkan deskripsi gambar di sini

brainydexter
sumber

Jawaban:

150

Dengan menentukan @JoinColumnpada kedua model Anda tidak memiliki hubungan dua arah. Anda memiliki dua hubungan satu arah, dan pemetaan yang sangat membingungkan pada saat itu. Anda memberi tahu kedua model bahwa mereka "memiliki" kolom IDAIRLINE. Benar-benar hanya satu dari mereka yang seharusnya melakukannya! Hal 'normal' adalah untuk mengambil @JoinColumnoff dari @OneToManysisi sepenuhnya, dan bukan menambah mappedBy ke @OneToMany.

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

Itu memberi tahu Hibernate "Lihatlah ke properti kacang bernama 'airline' pada benda yang saya punya koleksi untuk menemukan konfigurasi."

Affe
sumber
2
Saya sedikit bingung dengan deskripsi Anda pada akhirnya tentang dipetakan. Apakah penting bagaimana hal-hal diatur dalam db? @DB: AirlineFlights memiliki idAirline sebagai Kunci Asing. Maskapai hanya memiliki idAirline sebagai kunci Utama dan tidak mempertahankan info tentang AirlineFlights @ DB.
brainydexter
10
Ya itu penting. Nama di mappedBy memberitahu Hibernate di mana menemukan konfigurasi untuk JoinColumn. (Pada metode getAirline () dari AirlineFlight.) Cara Anda dipetakan itu menempatkan JoinColumn pada maskapai, Anda mengatakan Airline bahwa itu adalah bertanggung jawab untuk menjaga nilai-nilai lebih dalam tabel lainnya. Dimungkinkan untuk memberi tahu Entitas bahwa ia "memiliki" kolom dalam tabel yang berbeda dan bertanggung jawab untuk memperbaruinya. Ini bukan sesuatu yang biasanya ingin Anda lakukan dan dapat menyebabkan masalah dengan urutan pernyataan SQL dijalankan.
Affe
Silakan lihat hasil edit. Pada tingkat DB, airlineFlight table memiliki idAirline sebagai kolom kunci asing. Oleh karena itu, JoinColumn harus diletakkan pada kelas / tabel maskapai penerbangan di ManytoOne yang sesuai, karena ia memiliki kolom itu?
brainydexter
Ya, saya akan merekomendasikan melakukannya dengan cara itu. Ini adalah opsi yang paling tidak rumit dan Anda tampaknya tidak membutuhkan yang lain.
Affe
"lepaskan @JoinColumn dari sisi @OneToMany sepenuhnya" maksudmu dari @ManyToOnesisi itu, kan?
nbro
284

Sinyal MappedBy hibernate bahwa kunci untuk hubungan ada di sisi lain.

Ini berarti bahwa meskipun Anda menautkan 2 tabel bersama, hanya 1 tabel yang memiliki batasan kunci asing ke yang lain. MappedBy memungkinkan Anda untuk tetap menautkan dari tabel yang tidak mengandung batasan ke tabel lainnya.

Kurt Du Bois
sumber
3
bisakah Anda menjelaskan lebih banyak?
Alexander Suraphel
1
@Kurt Du Bois, mengapa Anda menggunakan mappedBydaripada mendefinisikan dua arah (dengan batasan foreign_key di setiap sisi)?
Kevin Meredith
6
Karena terkadang tidak masuk akal untuk meletakkan kunci di kedua sisi. Katakanlah misalnya Anda memiliki perusahaan dan perangkat portabel. Portable hanya akan menjadi milik satu perusahaan, tetapi perusahaan akan memiliki banyak portabilitas.
Kurt Du Bois
Maaf kepada orang yang mengedit karena memutar kembali jawaban saya, tetapi sebenarnya tidak ada nilai tambah sama sekali dalam edit Anda. Kalimat terakhir bahkan tidak masuk akal.
Kurt Du Bois
@ KurtDuBois jadi dipetakan dengan hanya datang ke gambar bagaimana membuat database Anda, yaitu apakah Anda menggunakan dipetakan atau tidak hibernasi di sisi java berperilaku serupa. Apakah itu?
22

mappedbyberbicara sendiri, ia memberi tahu hibernasi untuk tidak memetakan bidang ini. itu sudah dipetakan oleh bidang ini [nama = "bidang"].
bidang ada di entitas lain (name of the variable in the class not the table in the database)..

Jika Anda tidak melakukannya, hibernate akan memetakan dua relasi ini karena itu bukan relasi yang sama

jadi kita perlu memberi tahu hibernate untuk melakukan pemetaan di satu sisi saja dan berkoordinasi di antara mereka.

Charif DZ
sumber
Apakah pemetaan ini opsional? Karena tanpa menggunakan mappedBy saya mendapatkan hasil yang sama yaitu pemetaan objek dua arah
Freelancer
Anda tidak dapat menggunakan on2many dan many2one tanpa menggunakan mappedBy di salah satu sisi hal yang sama untuk many2many Anda harus menggunakan mappedBy di satu sisi
Charif DZ
Terima kasih telah menunjukkan apa arti nilai atribut yang merupakan nama bidang di tabel lainnya.
Gab 是 好人
2
Mungkin hibernasi tidak selalu berbicara untuk dirinya sendiri, tetapi ketika itu terjadi, setidaknya menggunakan tanda baca
Amalgovinus
1
Bagi saya, itu tidak berbicara untuk dirinya sendiri; sebaliknya, itu sangat membingungkan. Lihat saja sejumlah pertanyaan tentang apa yang sebenarnya mappedBydan inversedBy. ORMs lain menggunakan jauh lebih cerdas belongsToMany, hasManyatribut.
Jan Bodnar
12

mappedby = "objek entitas dari kelas yang sama yang dibuat di kelas lain”

Catatan: -Metakan hanya dapat digunakan dalam satu kelas karena satu tabel harus mengandung batasan kunci asing. jika dipetakan oleh dapat diterapkan di kedua sisi maka itu menghapus kunci asing dari kedua tabel dan tanpa kunci asing tidak ada hubungan b / w dua tabel.

Catatan: - dapat digunakan untuk anotasi berikut: - 1. @ OneTone 2. @ OneToMany 3. @ ManyToMany

Catatan --- Ini tidak dapat digunakan untuk anotasi berikut: - 1. @ ManyToOne

Dalam satu lawan satu: - Lakukan di setiap sisi pemetaan tetapi lakukan hanya di satu sisi. Ini akan menghapus kolom tambahan batasan kunci asing pada tabel di mana kelas itu diterapkan.

Untuk misalnya. Jika kita menerapkan pemetaan oleh kelas Karyawan pada objek karyawan maka kunci asing dari tabel Karyawan akan dihapus.

ks gujjar
sumber
12

Hubungan tabel vs hubungan entitas

Dalam sistem basis data relasional, one-to-manyhubungan tabel terlihat sebagai berikut:

hubungan tabel <code> satu-ke-banyak </code>

Perhatikan bahwa hubungan didasarkan pada kolom Kunci Asing (misalnya, post_id) di tabel anak.

Jadi, ada satu sumber kebenaran ketika datang untuk mengelola one-to-manyhubungan tabel.

Sekarang, jika Anda mengambil hubungan entitas dua arah yang memetakan pada one-to-manyhubungan tabel yang kita lihat sebelumnya:

Asosiasi entitas <code> Satu-Untuk-Banyak </code> dua arah

Jika Anda melihat diagram di atas, Anda dapat melihat bahwa ada dua cara untuk mengelola hubungan ini.

Di Postentitas, Anda memiliki commentskoleksi:

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

Dan, dalam PostComment, postasosiasi dipetakan sebagai berikut:

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

Karena ada dua cara untuk mewakili kolom Kunci Asing, Anda harus menentukan mana yang merupakan sumber kebenaran ketika harus menerjemahkan perubahan status asosiasi menjadi modifikasi nilai kolom Kunci Asing yang setara.

Dipetakan oleh

The mappedByatribut mengatakan bahwa @ManyToOnesisi bertugas mengelola kolom Foreign Key, dan koleksi hanya digunakan untuk mengambil entitas anak dan untuk kaskade perubahan induk entitas negara untuk anak-anak (misalnya, menghapus orang tua juga harus menghapus entitas anak).

Sinkronkan kedua sisi dari asosiasi dua arah

Sekarang, bahkan jika Anda mendefinisikan mappedByatribut dan @ManyToOneasosiasi sisi-anak mengelola kolom Kunci Asing, Anda masih perlu menyinkronkan kedua sisi dari asosiasi dua arah.

Cara terbaik untuk melakukannya adalah dengan menambahkan dua metode utilitas ini:

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

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

Metode addCommentdan removeCommentmemastikan kedua belah pihak disinkronkan. Jadi, jika kita menambahkan entitas anak, entitas anak perlu menunjuk ke induk dan entitas induk harus memiliki anak yang terkandung dalam koleksi anak.

Untuk detail lebih lanjut tentang cara terbaik untuk menyinkronkan semua jenis asosiasi entitas dua arah, lihat artikel ini .

Vlad Mihalcea
sumber
0

Anda mulai dengan pemetaan ManyToOne, lalu Anda meletakkan pemetaan OneToMany juga untuk cara BiDirectional. Kemudian di sisi OneToMany (biasanya tabel / kelas induk Anda), Anda harus menyebutkan "mappedBy" (pemetaan dilakukan oleh dan di tabel / kelas anak), jadi hibernate tidak akan membuat tabel pemetaan EXTRA di DB (seperti TableName = parent_child).

Akshay N. Shelke
sumber