Cascade ve İlişkinin Sahibi — Kalem Gerçekten Eklendi mi?
Önce şunu oku: Flush ve SQL Sırası — save() Satırında Neden Hiçbir Şey Olmuyor?
30 saniyede özet
Sipariş ile kalemleri iki yönden birbirini tanır, ama veritabanına yalnızca biri yazar: kalemdeki @ManyToOne. Öbür taraf sadece bir aynadır. Cascade kaydetmeyi taşır, orphanRemoval da listeden çıkanı siler.
Siparişe yeni kalem eklenen ekranda hata yoktu, ama kalem veritabanına hiç yazılmadı. Kalemi silen ekranda da hata yoktu, ama orada da tuhaf bir şey oluyordu.
-
Bayt: Siparişe kalem ekledim, ekranda görünüyordu. Veritabanına hiç yazılmamış!
-
Sen: Kalemi listeye eklemedin mi?
-
Bayt: Ekledim! order.getLines().add(kalem). Başka ne gerekiyordu ki?
-
Bayt: Bir çocuğun hangi sınıfta olduğunu liste mi belirler, kayıt formu mu?
İlişkiyi kim yazar?
Çift yönlü bir ilişkinin iki ucu vardır: Order.lines ve OrderLine.order. Yabancı anahtar order_lines tablosundadır ve onu yazan uç owning sideÇift yönlü bir ilişkide yabancı anahtarı yazan taraf; genellikle @ManyToOne. mappedBy ile işaretli taraf yalnızca bir aynadır; onu değiştirmek SQL üretmez.Sözlükte gör →, yani @ManyToOne tarafıdır.
mappedBy = "order" ile işaretli koleksiyon bir aynadır. Onu değiştirmek bellekteki nesneyi değiştirir; FK’ye dair hiçbir SQL üretmez.
public void addLine(OrderLine line) { lines.add(line); line.setOrder(this);}Kafam karıştı, daha basit anlat
İlişkinin iki ucu var ama kalemi yalnızca biri tutar. Veritabanına yazan uç kalemin tarafıdır. mappedBy olan taraf ise yalnızca bir aynadır: aynadaki görüntüyü değiştirmek asıl şeyi değiştirmez.
Order'da @OneToMany(mappedBy = "order") List<OrderLine> lines, OrderLine'da @ManyToOne Order order var. order_id sütununu hangi alan belirler?
cascade = ALL açık. Kod yalnızca order.getLines().add(newLine) yapıyor, newLine.setOrder(order) çağırmıyor. order_id NOT NULL. Ne olur?
Birlikte kaydet, birlikte sil
cascadeBir entity'ye yapılan işlemin (persist, merge, remove…) ilişkideki entity'lere de uygulanması. Yalnızca parçası olduğu bütünle birlikte yaşayan çocuklar için kullanılır.Sözlükte gör →, ebeveyne yapılan işlemi çocuklara taşır: sipariş persist edilince yeni kalemler de persist edilir. Cascade yoksa yeni kalem ancak kendisi persist edilirse kaydedilir.
orphanRemoval kapalı. order.getLines().remove(kalem) çağrıldı ve commit edildi. Kalem veritabanından silinir mi? Cevabı göster
Hayır. mappedBy tarafındaki koleksiyondan çıkarmak SQL üretmez. Kalem veritabanında durur ve sipariş yeniden yüklenince geri gelir.
Adım adım oku
- Kalemi yalnızca Order.lines listesine eklemek, sınıf listesine isim yazmaktır: veritabanında kayıt oluşmaz.
- OrderLine.order alanı, yani kayıt formu doldurulunca yabancı anahtar yazılır ve kalem kaydedilir.
- orphanRemoval kapalıyken kalemi listeden çıkarmak kaydı silmez; kalem veritabanında durmaya devam eder.
- orphanRemoval açıkken listeden çıkan kalem sahipsiz kabul edilir ve silinir.
orphanRemovalKoleksiyondan çıkarılan ya da ebeveyniyle bağı koparılan çocuğun veritabanından silinmesi. cascade REMOVE'dan farklıdır: o, ebeveyn silinince çalışır.Sözlükte gör → = true, koleksiyondan çıkan çocuğu siler. cascade = REMOVE ise yalnızca ebeveyn silinince çalışır.
Kafam karıştı, daha basit anlat
Cascade, “siparişe ne yaparsan kalemlerine de yap” demektir. Kalemi listeden çıkarmak ise onu silmez; silinmesini istiyorsan orphanRemoval gerekir.
orphanRemoval yok. order.getLines().remove(line) çağrıldı, transaction commit edildi. Veritabanında ne olur?
cascade = REMOVE ile orphanRemoval = true arasındaki fark nedir?
Kendin gör
Kalem gerçekten eklendi mi?
Tohum 947319Oynat ya da adımla.
Şu an ne oldu?
Order.lines tarafı mappedBy: yalnızca bir ayna
Yabancı anahtarı OrderLine.order yazar. Koleksiyonu değiştirmek, sahip tarafı değiştirmek değildir.
Görevler0/3
Yeni kalemi order_id = NULL ile kaydetmeye çalışaçık
İpucu
Cascade açık, ama yalnızca koleksiyona ekle.
Koleksiyondan çıkardığın kalem veritabanında kalsınaçık
İpucu
orphanRemoval kapalı, sahip tarafa dokunma.
Ekle ve çıkar; bellek ile veritabanı aynı kalsınaçık
İpucu
Yardımcı metot, cascade ve orphanRemoval.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Cascade ALL, yalnızca koleksiyon: yeni kalem order_id NULL ile patladı, eski kalem hayalet kaldı.
- “İki tarafı da güncelle”yi aç. Ekleme düzeldi; çıkarma şimdi NULL’a güncellemeye çalıştı.
- orphanRemoval’ı aç. İkisi de doğru.
- cascade’i “Yok” yap. Yeni kalem hiç kaydedilmedi.
Bir kalemi silen kod, ürün kataloğundan da ürünü siliyor. Hatalı satır hangisi?
Her ilişkiyi cascade ve orphanRemoval açısından ayır.
Tuzaklar
Paylaşılan entity’ye cascade. Kalemden ürüne cascade = ALL, bir kalemi silerken ürünü katalogdan siler. Cascade yalnızca ebeveynden, onunla birlikte ölen çocuğa doğru kurulur.
Koleksiyonu yenisiyle değiştirmek. orphanRemoval’lı bir koleksiyona setLines(new ArrayList<>()) hata verir. Mevcut koleksiyonu clear() edip doldur ya da setter yazma.
Büyük koleksiyonda cascade REMOVE. Hibernate her çocuğu yükler ve tek tek siler. Binlerce çocuk için bilinçli bir toplu silme gerekir.
Kafam karıştı, daha basit anlat
Cascade’i yalnızca ebeveynden, onunla birlikte yaşayıp ölen çocuğa kur. Ürün kataloğu gibi başkalarıyla paylaşılan şeylere asla kurma.
orphanRemoval = true olan bir ilişkide order.setLines(new ArrayList<>(dtoLines)) yazıldı. Hibernate hata veriyor. Neden?
Aşağıdaki örnek bir bankanın kurumsal müşterilere sunduğu toplu ödeme talimatından; aggregate doğru eşleniyor: iki tarafı birlikte güncelleyen metotlar, yalnızca aggregate içinde cascade, koleksiyonu değiştirmeden yenileme ve bunları veritabanından yeniden okuyarak doğrulayan test.
Derinleş · Toplu ödeme talimatı aggregate'i: sahip taraf, cascade ve orphanRemoval 5 dosya · ~127 satır · ilk okumada atlayabilirsin
Kendini sına
Çift yönlü bir ilişkide yabancı anahtarı @ManyToOne tarafı yazar.
Tek yönlü @OneToMany List<OrderLine> lines (mappedBy ve @JoinColumn olmadan) yazdın. Şema oluşturulunca ne görürsün?
Aklında kalacak üç şey
- 1 Çift yönlü ilişkide order_id sütununu OrderLine.order yazar. Yalnızca listeye eklemek o sütunu boş bırakır; iki tarafı birlikte güncelleyen bir yardımcı metot gerekir.
- 2 mappedBy tarafındaki listeden bir şey çıkarmak SQL üretmez. Çocuğun silinmesi için orphanRemoval = true gerekir.
- 3 Cascade yalnızca ebeveyniyle birlikte yaşayıp ölen çocuklar içindir. Ürün ya da müşteri gibi paylaşılan kayıtlara cascade REMOVE koymak veri siler.
5 kart sonraki derste seni bekliyor