18 Eylül 2019 Çarşamba

JPA @MappedSuperclass Anotasyonu - Tablo Yaratmaz, Polymorphic Sorgu İçin Uygun Değildir

Giriş
Şu satırı dahil ederiz.
import javax.persistence.MappedSuperclass;
Açıklaması şöyle. Veri tabanı açısından kalıtım yoktur, sadece kod açısından kalıtım vardır. Bu yüzden @Inheritance ile farklıdır.
@MappedSuperclass tells the JPA provider to include the base class persistent properties as if they were declared by the child class extending the superclass annotated with @MappedSuperclass.

However, the inheritance is only visible in the OOP world, since, from a database perspective, there's no indication of the base class. Only the child class entity will have an associated mapped table.

The @Inheritance annotation is meant to materialize the OOP inheritance model in the database table structure. More, you can query a base class annotated with @Inheritance but you can't do that for a base class annotated with @MappedSuperclass.
JPA bu anotasyonun sadece @Entity sınıfları için kullanılmasını tanımlıyor.

Zayıf Tarafı Nedir?
Açıklaması şöyle. Elimizde Foo ve bundan kalıtan Bar sınıfı olsun. Veri tabanı açısından kalıtım olmadığı için bana tüm Foo'ları ver dersem Bar nesnelerini çekemem. Polymorphic sorgu için @Inheritance kullanılmalı.
The main problem with this mapping strategy is that it doesn't easily support polymorphism in Java code. For example, we cannot execute a query on the superclass Publication so that it covers both tables of its subclasses. If the application does not really need such queries, and will explicitly query the specific subclasses, then this approach may be suitable.
Örnek
Elimizde şöyle bir kod olsun. Bana tüm Publicaiton'ları ver dersem Magazine nesnelerini çekemem.
@MappedSuperclass
public abstract class Publication {
    @Id
    @GeneratedValue(generator = "idGenerator")
    ... // declare idGenerator here or in a shared package-info.java
    protected Long id;

    @Column(nullable = false)
    protected String title;

    @ManyToOne
    @JoinColumn(name = "PUBLISHER_ID", nullable = false)
    protected Publisher publisher;

    @Temporal(TemporalType.DATE)
    protected Date publishingDate;
    ...
}

@Entity
public class Magazine extends Publication {

    protected int issueNumber;

    @Enumerated(EnumType.STRING)   // store the enum value as string
    protected Schedule schedule;
    ...
}
Magazine için üretilen SQL şöyledir ve foreign key ile Publication'a bağlanmamıştır.
create table Magazine (
    id bigint not null,
    publishingDate date,
    title varchar(255) not null,
    issueNumber integer not null,
    schedule varchar(255),
    PUBLISHER_ID bigint not null,
    primary key (id)
)

Örnek
Şöyle yaparız. Aslında bu örnekte ata sınıfı abstract yapmakta fayda var
@MappedSuperClass
class MotherOfAllEntities {
   @Embedded
   Audit audit;
}

@Entity
class ChildClass extends MotherOfAllEntities {
}
Diğer
JPA normalde @Embeddable için kalıtımı desteklemiyor. Açıklaması şöyle.
...The JPA spec does not support embeddable objects having inheritance, although some JPA providers may allow this.
Ancak Hibernate kullananlar bu anostasyon ile kalıtım yapabildiğini söylüyor.

1. Şöyle yaparız.
2. Şöyle yaparız.

Bazıları ise bu anotasyonun çalışmadığını söylüyor.
1. Şöyle yapamayız.

Ben de bu anotasyonu eklediğimde çalışmadığını gördüm. Anotasyon olmadan iki tane @Embeddable arasında kalıtım kullandığımda Hibernate sorunsuz çalıştı. En iyisi JPA uyumlu olmak ve kalıtım kullanmamak.

Soft Delete
Şöyle yaparız. Diğer sınıfları bu atadan kalıtırız.
@MappedSuperclass
abstract class AbstractEntity {
  @Column(name = "deleted_ind", nullable = false)
  Boolean deleted = Boolean.FALSE
}

Hiç yorum yok:

Yorum Gönder