Hangi ek açıklamayı kullanmalıyım: @IdClass veya @EmbeddedId


129

JPA(Java Persistence API) şartname varlık kompozit anahtarları belirtmek için 2 farklı yolları vardır: @IdClassve @EmbeddedId.

Eşlenen varlıklarımda her iki ek açıklamayı da kullanıyorum, ancak çok aşina olmayan insanlar için büyük bir karışıklık olduğu ortaya çıkıyor JPA.

Bileşik anahtarları belirtmenin yalnızca bir yolunu kullanmak istiyorum. Hangisi gerçekten en iyisi? Neden?

Yanıtlar:


87

Bunun @EmbeddedIdmuhtemelen daha ayrıntılı olduğunu düşünüyorum çünkü @IdClassherhangi bir alan erişim operatörünü kullanarak birincil anahtar nesnesinin tamamına erişemezsiniz. Kullanılması @EmbeddedIdböyle yapabilirsiniz:

@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
  @EmbeddedId EmployeeId employeeId;
  ...
}

Bu, bileşik anahtarı oluşturan alanların net bir fikrini verir, çünkü bunların tümü bir alan erişim operatörü aracılığıyla erişilen bir sınıfta toplanır.

HQL yazmak söz konusu olduğunda @IdClassve ile diğer bir fark @EmbeddedId:

Seninle @IdClassyaz:

Employee'den e.name seçin e

ve @EmbeddedIdseninle yazmalısın:

Employee e'den e.employeeId.name seçin

Aynı sorgu için daha fazla metin yazmanız gerekiyor. Bazıları bunun, desteklediği gibi daha doğal bir dilden farklı olduğunu iddia edebilir IdClass. Ancak çoğu zaman, belirli bir alanın bileşik anahtarın bir parçası olduğunu sorgulamadan anlamak paha biçilemez bir yardımdır.


10
Yukarıda verilen açıklamayı kabul @IdClassetsem de @EmbeddedId, çoğu durumda tercih etsem de benzersiz bir kullanım durumu eklemek istiyorum (Bunu Antonio Goncalves'in yaptığı bir oturumdan öğrendim. Onun önerdiği şey @IdClass, kompozit anahtar sınıf erişilebilir değil veya ek açıklama ekleyemediğimiz başka bir modülden veya eski koddan geliyor. Bu senaryolarda @IdClassbize bir yol gösterecek.
Gaurav Rawat

1
@IdClass@Gaurav tarafından verilen ek açıklamayı kullanma durumlarının , JPA spesifikasyonunun bir bileşik anahtar oluşturmanın her iki yöntemini de listelemesinin tam nedeni olabileceğini düşünüyorum .. @IdClassve@EmbeddidId
kapad

20

Bileşik birincil anahtar kullanmak için üç strateji vardır:

  • Olarak işaretleyin @Embeddableve varlık sınıfınıza, ile işaretlenmiş normal bir özellik ekleyin @Id.
  • Varlık sınıfınıza onun için ile işaretlenmiş normal bir özellik ekleyin @EmbeddedId.
  • Tüm alanları için varlık sınıfınıza özellikler ekleyin, bunları ile @Idişaretleyin ve varlık sınıfınızı ile işaretleyerek @IdClassbirincil anahtar sınıfınızın sınıfını sağlayın.

Olarak @Idişaretlenmiş bir sınıfla @Embeddablekullanılması en doğal yaklaşımdır. @EmbeddableEtiket zaten birincil olmayan anahtar gömülebilir değerleri için kullanılabilir. Bileşik birincil anahtarı tek bir özellik olarak ele almanıza olanak tanır ve @Embeddablesınıfın diğer tablolarda yeniden kullanımına izin verir .

Bir sonraki en doğal yaklaşım, @EmbeddedIdetiketin kullanılmasıdır. Burada, birincil anahtar sınıfı bir @Embeddablevarlık olmadığı için diğer tablolarda kullanılamaz , ancak anahtarı bir sınıfın tek bir özniteliği olarak ele almamıza izin verir.

Son olarak, @IdClassve @Idek açıklamalarının kullanımı, birincil anahtar sınıfındaki özelliklerin adlarına karşılık gelen varlığın özelliklerini kullanarak bileşik birincil anahtar sınıfını eşlememize olanak tanır. İsimler uygun olmalıdır (bunu geçersiz kılacak bir mekanizma yoktur) ve birincil anahtar sınıf diğer iki teknikle aynı yükümlülükleri yerine getirmelidir. Bu yaklaşımın tek avantajı, birincil anahtar sınıfının kullanımını çevreleyen varlığın arayüzünden "gizleyebilme" yeteneğidir. @IdClassAçıklama sınıf bileşik birincil anahtar olarak kullanılacak olması gerekir Sınıf türü bir değer parametre alır. Kullanılacak birincil anahtar sınıfının özelliklerine karşılık gelen alanların tümüne açıklama eklenmelidir @Id.

Referans: http://www.apress.com/us/book/9781430228509


17

IdClass yerine EmbeddedId kullanmam gereken bir örnek keşfettim. Bu senaryoda, tanımlanmış ek sütunlara sahip bir birleştirme tablosu vardır. Bu sorunu, birleştirme tablosundaki satırları açıkça temsil eden bir varlığın anahtarını temsil etmek için IdClass kullanarak çözmeye çalıştım. Bu şekilde çalışmasını sağlayamadım. Neyse ki "Java Persistence With Hibernate" bu konuya ayrılmış bir bölüme sahip. Önerilen bir çözüm benimkine çok benziyordu ancak onun yerine EmbeddedId kullandı. Nesnelerimi kitaptakilerden sonra modelledim, şimdi doğru davranıyor.


13

Bileşik PK'nizin FK içerip içermediğini bildiğim kadarıyla, kullanımı daha kolay ve daha kolay @IdClass

İle , iki değişkende bir sütun kümeniz olamaz (olası çakışmalar) nedeniyle @EmbeddedId, FK sütununuz için iki kez, bir tek giriş @Embeddedableve bir kez, yani @ManyToOnenerede @ManyToOnesalt okunur ( @PrimaryKeyJoinColumn) olması gerektiği için eşlemeyi tanımlamanız gerekir.
Bu nedenle, FK'nizi basit yazım kullanarak ayarlamanız gerekir @Embeddedable.

Diğer sitede, @IdClassbu durumu kullanmak , OneToOne ve ManyToOne İlişkileri aracılığıyla Birincil Anahtarlarda gösterildiği gibi çok daha kolay ele alınabilir :

Örnek JPA 2.0 ManyToOne kimlik ek açıklaması

...
@Entity
@IdClass(PhonePK.class)
public class Phone {

    @Id
    private String type;

    @ManyToOne
    @Id
    @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
    private Employee owner;
    ...
}

Örnek JPA 2.0 kimlik sınıfı

...
public class PhonePK {
    private String type;
    private long owner;

    public PhonePK() {}

    public PhonePK(String type, long owner) {
        this.type = type;
        this.owner = owner;
    }

    public boolean equals(Object object) {
        if (object instanceof PhonePK) {
            PhonePK pk = (PhonePK)object;
            return type.equals(pk.type) && owner == pk.owner;
        } else {
            return false;
        }
    }

    public int hashCode() {
        return type.hashCode() + owner;
    }
}

1
PK sınıfınıza alıcı eklemeyi unutmayın
Sonata

@Sonata alıcılara neden ihtiyacımız var? Herhangi bir alıcı / ayarlayıcı olmadan denedim ve iyi çalışıyor
xagaffar

İd sınıfı örneği için teşekkürler! Yine de Serializable'ı uygulamaya ihtiyacım vardı. Ayrıca alıcılar ve ayarlayıcılar da ekleyebilir, özellikle de IDE'niz bunları otomatik olarak oluşturabiliyorsa.
Starwarswii

8

Ben ana avantajı kullandığımız olabilir olduğunu düşünüyorum @GeneratedValuekullanırken kimliği için @IdClass? Bence kullanamaz eminim @GeneratedValueiçin @EmbeddedId.


1
Embeddedid'de @GeneratedValue kullanmak mümkün değil mi?
Kayser

1
Bunu EmbeddedId ile başarılı bir şekilde kullandım ancak görünüşe göre desteği DB'ye göre değişiyor. Bu aynı zamanda IdClass ile kullanmak için de geçerlidir. Spesifikasyonda: "GeneratedValue ek açıklaması yalnızca basit (yani, bileşik olmayan) birincil anahtarlar için taşınabilir şekilde kullanılabilir."
BPS

4

Bileşik Anahtar kullanıldığında bir @Idözelliğe sahip olmamalıdır @EmbeddedId.


1

EmbeddedId FROM Entity WHERE id IN :idsile HQL'de IN cümlesini kullanabilirsiniz, örneğin: burada id bir EmbeddedId iken, IdClass ile aynı sonucu elde etmek acıdır, buna benzer bir şey yapmak isteyeceksiniz.FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

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.