2015-09-28 18 views
7

Hazırda bekletme durumunun çoktan tekil bir ilişkide beklenen varlık türünü yaratmadığı garip bir sorun var. persistence.xml yılındaHazırda yanlış varlık alt türü oluşturma hazırda beklemede

@Entity 
@Table(name = "A") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1) 
public abstract class A { 

    @Id 
    ... 
    public Long getId() { ... } 
    ... 
} 

@Entity 
@DiscriminatorValue("1") 
public class A1 extends A { 
    ... 
} 

@Entity 
@DiscriminatorValue("2") 
public class A2 extends A { 
    ... 
} 


@Entity 
@Table(name = "B") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1) 
public abstract class B<AClass extends A> { 

    protected AClass a; 

    @Id 
    ... 
    public Long getId() { ... } 
    ... 

    public abstract AClass getA(); 
    public void setA(AClass a) { ... } 
} 

@Entity 
@DiscriminatorValue("1") 
public class B1 extends B<A1> { 
    ... 

    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A_ID") 
    public A1 getA() { ... } 
} 

@Entity 
@DiscriminatorValue("2") 
public class B2 extends B<A2> { 
    ... 

    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A_ID") 
    public A2 getA() { ... } 
} 

her iki tarafın

A2 
A1 
B2 
B1 

Şimdi DB A1 örneklerini ve B1 oluşturmak amacıyla ilan edilir:

Biz (basitleştirilmiş) alt sınıf hiyerarşisi ile aşağıdaki varlıklara sahip
A1 a1 = new A1(); 
entityManager.persist(a1); 
B1 b1 = new B1(); 
b1.setA(a1); 
entityManager.persist(b1); 

Örneklerin her biri kimlik 1'e sahip olan DB'ye doğru kaydedildiğini görüyorum, AYRIMCI ayrıca 1, B'de de A_ID 1'dir.

Şimdi (başka hazırda oturumda) B almaya çalıştığınızda

: Ben hazırda doğru bir varlık yaratıyor öğrendim ayıklama ile

org.hibernate.PropertyAccessException: Exception occurred inside getter of B 
Caused by: java.lang.ClassCastException: A2 cannot be cast to A1 
at B1.getA(B1.java:61) 
... 108 more 

:

B b = entityManager.find(B.class, 1L); 

özel durum almak B1 yazın ve A ile ilişki için A2 türünde yanlış bir öğe oluşturur. persistence.xml'daki sipariş değiştiyse doğru tip A1 oluşturulur. Hazırda bekletme, bu durumda A tablosunun DISCRIMINATOR sütununu dikkate almaz gibi görünüyor, ancak her zaman yapılandırmada bildirilen ilk alt türü oluşturur. Bu nasıl düzeltilebilir? Ek açıklamalarla ilgili bir sorun mu var?

(Ben de ilk başta süper tip B yılında ek açıklamalarla yöntemin getA() somut uygulama vardı, ama bu benzer sorunlara yol açar.)

cevap

3

Hazırda bekletme 5.0.2.Final ile örnek çalışmalarınızı @ManyToOne(..., targetEntity = A.class) kullanarak yapabildim. Ayrıca public abstract AClass getA();'u sıradan bir alıcı ile değiştirdim.

@Entity 
@DiscriminatorValue("1") 
public class B1 extends B<A1> { 
    // no need to override getA() 
} 
@Entity 
@DiscriminatorValue("2") 
public class B2 extends B<A2> { 
    // no need to override getA() 
} 

@Entity 
@Table(name = "B") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1) 
public abstract class B<AClass extends A> { 
    private Long id; 
    private AClass a; 

    @Id 
    @GeneratedValue 
    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    @ManyToOne(fetch = FetchType.EAGER, targetEntity = A.class) 
    @JoinColumn(name = "A_ID") 
    public AClass getA() { 
     return a; 
    } 

    public void setA(AClass a) { 
     this.a = a; 
    } 
} 
ben belgelerinde bu davranış hakkında bir şey bulamadık.Yani sadece benim gözlemlerim var: Zaten A gerçek türü hakkında bir karara gibi hevesle, B birlikte A satırları getirilirken

  • targetEntity = A.class olmadan hazırda bile masanın A ait DISCRIMINATOR sütun sorgulamak vermedi.
  • targetEntity = A.class eklendiğinde, A.DISCRIMINATOR sorgularda görüntülendi ve nesneler, A sınıfının sağ alt sınıflarıyla oluşturuldu.
+0

Cevabınız için teşekkür ederiz. Dün bunu test etme şansım oldu ve bu sorunun senaryosunda çalışıyorum :) – Gandalf

3

Her iki B1 aynı katılmak sütunu (A_ID) kullanıyor ve B2 alt sınıflar.

her alt sınıfta

kullanın farklı bir: o (farklı sütunlu bir zaten alt sınıfına bağlı olarak her kayıt için null olacaktır) sütununu yeniden mantıklı olsa

@Entity 
@DiscriminatorValue("1") 
public class B1 extends B<A1> { 
    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A1_ID") 
    public A1 getA() { ... } 
} 

@Entity 
@DiscriminatorValue("2") 
public class B2 extends B<A2> { 
    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A2_ID") 
    public A2 getA() { ... } 
} 

, bu hazırda kullandığı gibi görünüyor Sütun adları, aynı tablo içindeki bazı eşleme öğelerini benzersiz şekilde tanımlamak için dahili olarak. Bu nedenle, büyük olasılıkla B1'daki bire-bir eşlemenin tanımını yok sayar ve bunun için de B2'dan birini kullanır (çünkü B2, , persistence.xml'da tanımlanmıştır).

+0

Cevabınız için teşekkürler Dragan! :) Diğer cevaplar işe yaradığı ve bazı avantajları olduğu için çalışıp çalışmadığını test etmek için zamanım olmadı: 1. Daha az kod. 2. Daha az DB sütunları 3. DB sütunundaki null ve yabancı anahtar kısıtlamalarını tutamazız. – Gandalf

İlgili konular