Tek Yönlü ve Çift Yönlü JPA ve Hazırda Bekletme ilişkilendirmeleri arasındaki fark nedir?


135

Tek Yönlü ve Çift Yönlü ilişkilendirmeler arasındaki fark nedir?

Db'de oluşturulan tablo hepsi aynı olduğundan, bulduğum tek fark, çift yönlü varsayımların her bir tarafının diğerine atıfta bulunması ve tek yönlü olmamasıdır.

Bu Tek Yönlü bir ilişkilendirmedir

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}

public class Group {
    private int     id;
    private String  name;
}

Çift yönlü ilişki

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}
public class Group {
    private int         id;
    private String      name;
    @OneToMany(mappedBy="group")
    private List<User>  users;
}

Fark, grubun kullanıcının referansını tutup tutmamasıdır.

Acaba tek fark bu mu? hangisi önerilir?


7
Grup şimdi hangi kullanıcıları içerdiğini bilecek. Bunun hiçbir şekilde küçük bir fark olduğunu düşünmüyorum.
Satadru Biswas

5
Güncelleme söz konusu olduğunda çift yönlü ilişkiler benim için bir karmaşa haline geldi. :)
diyoda_

Yanıtlar:


152

Ana fark, çift yönlü ilişkinin her iki yönde de gezinme erişimi sağlamasıdır, böylece diğer tarafa açık sorgular olmadan erişebilirsiniz. Ayrıca her iki yöne basamaklı seçenekler uygulamanızı sağlar.

Gezinme erişiminin her zaman iyi olmadığını unutmayın, özellikle "bire çok" ve "çoktan çoğa" ilişkileri için. GroupBinlerce Users içeren bir düşünün :

  • Onlara nasıl erişirdiniz? Pek çok Users ile, genellikle bir sorgulama ve / veya sayfalandırma uygulamanız gerekir, böylece yine de bir sorgu yürütmeniz gerekir ( benim için bir saldırı gibi görünen toplama filtrelemesi kullanmıyorsanız ). Bazı geliştiriciler bu gibi durumlarda bellekte filtreleme uygulama eğilimindedir, bu da performans için iyi değildir. Böyle bir ilişkiye sahip olmanın, bu tür geliştiricileri performans sonuçlarını düşünmeden kullanmaya teşvik edebileceğini unutmayın.

  • 'Ye nasıl yeni Users eklersiniz Group? Neyse ki, Hazırda Beklet, devam ederken ilişkinin sahibi tarafına bakar, böylece yalnızca ayarlayabilirsiniz User.group. Ancak, bellekteki nesneleri tutarlı tutmak istiyorsanız, eklemeniz Usergerekir Group.users. Ancak, Hibernate'i Group.usersveritabanının tüm öğelerini almak için yapar!

Bu nedenle, En İyi Uygulamalardan gelen öneriyi kabul edemem . Kullanım durumlarını (her iki yönde de navigasyon erişimine ihtiyacınız var mı?) Ve olası performans sonuçlarını göz önünde bulundurarak, çift yönlü ilişkileri dikkatli bir şekilde tasarlamanız gerekir.

Ayrıca bakınız:


Merhaba, teşekkürler, sorularıma cevap verdiğiniz için hazırda bekleme uzmanı olduğunuz anlaşılıyor: stackoverflow.com/questions/5350770/… . Ve şimdi ben burada yazılan olamaz yazma daha yorumunda, bu yüzden beri, emin ilişki tutma değilim dpaste.de/J85m zarar bulursanız çek mümkünse var :).
hguser

@hguser: Sonunda size ilişki çift yönlü yapmaya karar verirseniz, bunu daha iyi çağrısına olacağını düşünüyorum setGroup()gelen addUser()her iki tarafın da tutarlı tutmak amacıyla.
axtavt

group.addUser () içindeki setGroup () yöntemini çağırmazsam ne olur?
hguser

@hguser: İlişki devam etmezdi, cevabın 2. maddesine bakınız. setGroup()Olmadan arayabilirsiniz addUser(), ancak bellekteki nesnelerin tutarsız durumuna neden olur.
axtavt

Doğru bir harita bulamadığımı fark ettim, github'daki projemi kontrol etmek için biraz zaman ayırabilir misin? küçük bir proje.
hguser

31

İki ana fark vardır.

İlişkilendirme taraflarına erişim

Birincisi, ilişkiye nasıl erişeceğinizle ilgilidir. Tek yönlü bir ilişkilendirme için ilişkilendirmede yalnızca bir uçta gezinebilirsiniz.

Yani, tek yönlü bir @ManyToOneilişki için, ilişkiye yalnızca yabancı anahtarın bulunduğu alt taraftan erişebileceğiniz anlamına gelir.

Tek yönlü bir @OneToManyilişkilendirmeniz varsa, ilişkiye yalnızca yabancı anahtarın bulunduğu üst taraftan erişebileceğiniz anlamına gelir.

Çift yönlü @OneToManyilişkilendirme için ilişkilendirmede üst veya alt tarafından her iki şekilde de gezinebilirsiniz.

Her iki tarafın da düzgün şekilde senkronize olduğundan emin olmak için çift yönlü ilişkilendirmeler için ekleme / kaldırma yardımcı programı yöntemlerini kullanmanız gerekir .

Verim

İkinci husus performansla ilgilidir.

  1. Çünkü @OneToMany, tek yönlü ilişkilendirmeler hem çift yönlü olanlar kadar iyi performans göstermez .
  2. Çünkü @OneToOne, Hazırda Bekletme Proxy'nin atanıp atanmayacağını veya boş bir değer olup olmadığını söyleyemezse , çift ​​yönlü ilişkilendirme üst öğenin hevesle getirilmesine neden olur .
  3. İçin @ManyToMany, toplama tipi oldukça fark olarak yapar Setsdaha iyi performansLists .

11

Kodlama açısından, çift yönlü bir ilişkinin uygulanması daha karmaşıktır, çünkü uygulama, her iki tarafı da JPA spesifikasyonu 5'e göre senkronize tutmaktan sorumludur (sayfa 42). Maalesef şartnamede verilen örnek daha fazla ayrıntı vermez, bu nedenle karmaşıklık seviyesi hakkında bir fikir vermez.

İkinci düzey bir önbellek kullanılmadığında, örnekler işlemin sonunda atıldığı için ilişki yöntemlerinin doğru bir şekilde uygulanmaması genellikle sorun değildir.

İkinci düzey önbellek kullanıldığında, yanlış uygulanan ilişki işleme yöntemleri nedeniyle herhangi bir şey bozulursa, bu diğer işlemlerin de bozuk öğeleri göreceği anlamına gelir (ikinci düzey önbellek geneldir).

Doğru şekilde uygulanan iki yönlü bir ilişki, sorguları ve kodu daha basit hale getirebilir, ancak iş mantığı açısından gerçekten mantıklı değilse kullanılmamalıdır.


9

Bunun tek fark olduğundan% 100 emin değilim , ama ana fark bu. Ayrıca, Hazırda Bekletme dokümanları tarafından iki yönlü ilişkilendirmelerin olması önerilir:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

özellikle:

Çift yönlü ilişkilendirmeleri tercih et: Tek yönlü ilişkilendirmeleri sorgulamak daha zordur. Büyük bir uygulamada, hemen hemen tüm ilişkilendirmeler sorgularda her iki yönde de gezilebilir olmalıdır.

Ben şahsen bu battaniye önerisi ile hafif bir sorun var - benim bir çocuğun kendi üst hakkında bilmek herhangi pratik bir neden yoktur durumlar da vardır görünüyor (örneğin neden bir sipariş öğe yok ihtiyaç olduğunu sipariş hakkında bilmek ile ilişkili?), ancak değeri de makul bir süre görüyorum. Ve iki yönlü olma gerçekten hiçbir şeye zarar vermediği için, ona uymak için çok sakıncalı bulmuyorum.


Axtavt'ın açıkladığı gibi, çift yönlülük bazı durumlarda acıtabilir! Bir Hazırda Bekletme varlığında eşleştirilen her ilişki için çok dikkatli olurum! Ne yaptığınızı tam olarak bilmiyorsanız, Hazırda Bekleme'ye bir şeyler yüklemek için gereken sonsuz zamanla sonuçlanabilirsiniz. Kullanım durumlarını dikkatlice düşünün ve farklı kullanım durumları için farklı model sınıfları kullanın. F.ex. bir şey listesinde, ilgili tüm nesnelere ihtiyacım yok, sadece bir etikete ve kimliğe ihtiyacım var. Bu yüzden liste varlığı benim için detay varlıktan farklı (ve çok basit).
cslotty
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.