16 Eylül 2019 Pazartesi

JPA @ElementCollection Anotasyonu

Giriş
list,set, map gibi dizileri farklı bir tabloda saklamayı sağlar. JPA 2 ile geliyor. Bu anotasyon sadece primitive tipler (enumeration da olabilir) veya @Embeddable olarak işaretli sınıflar ile kullanılabilir.

@Entity olarak işaretli sınıflar için kullanmayın! @Entity'ler için yine @OneToMany kullanmak gerekir.

@CollectionTable İle Birlikte Kullanılır
Bu anotasyon @CollectionTable ile birliktedir. Eğer liste olarak kullanıyorsak sırayı korumak için @OrderColumn ile kullanılabilir.

Örnek
Açıklaması şöyle.
@CollectionTable specifies a name for the table (CONTENT_TAG) that will store the tags, along with a foreign key column BOOK_ID via the @JoinColumn in the collection table. Finally, the @Column defines the name of the column storing the actual tag strings, and also marks it as non-nullable.
Elimizde şöyle bir kod olsun.
@Entity
public class Book {
    @ElementCollection
    @CollectionTable(name = "CONTENT_TAG",
                 joinColumns = @JoinColumn(name = "BOOK_ID"))
    @Column(name = "TAG", nullable = false)
    protected Set<String> contentTags = new HashSet<>();
    ...
}
Tablo şöyledir. Book tablosundaki primary key alanına atıfta bulunur.
create table CONTENT_TAG (
   BOOK_ID bigint not null,
   TAG varchar(255) not null,
   primary key (BOOK_ID, TAG)
)

alter table CONTENT_TAG
   add constraint FKitxsi0kpxsoexvnjlnlxmgci7
   foreign key (BOOK_ID)
   references Book
Örnek
Parent tarafında şöyle yaparız. @JoinColum ile belirtilen sütun parent tarafındaki primary key alanıdır.
@ElementCollection
@CollectionTable(name="user_page", joinColumns=@JoinColumn(name="id_user"))
@Column(name="id_page")
public Set<Long> pageIds;
Örnek
Şöyle yaparız.
@ElementCollection
private Collection<String> strings;
@ElementCollection İçin Yaratılan Tablo
@ElementCollection ile join table yaratılmaz çünkü Element tarafının @Basic veya @Embedded olduğu yani id alanına sahip olmadığı kabul edilir. Bu anlamda unidirectional OneToMany gibidir. Child nesnelerin hayatı Parent nesneye bağlıdır. Child nesnenin id alanı olmadığı için tek bir nesneyi silme,güncelleme işlemi mümkün değil. Bu yüzden maliyetli olabilir.

@ElementCollection'dan Parent Nesneye Erişim
Normalde Child nesneden Parent nesneye erişime gerek yoktur. Ancak olsun istersek iki tane şey yapmak gerekir.

1. Child nesneye şöyle yaparız. Böylece @CollectionTable ile belirtilen tabloya child için de bir çeşit primary key alanı eklenir. Yani child'dan parent'a gitmek için bir sütun daha eklenir.
@ManyToOne
@JoinColumn (name="PARENT_ID")
private Parent parent;
2. Id'sini bildiğimiz Child'dan parent'a gitmek için SQL ile şöyle yaparız. Bu sql ile parent sınıfların ismi listelenir.
"SELECT c.name FROM Child c JOIN Parent p ON c.parent_id = p.id WHERE c.id  = ?"
fetch Alanı
Şöyle yaparız.
@ElementCollection(fetch = FetchType.EAGER)
private Map<String, Object> params;
targetClass Alanı
Eğer generic olmayan veriyapısı kullanıyorsak taşıdğı tipi belirtmek için kullanılır. Şöyle yaparız.
@ElementCollection(targetClass = Casting.class)
@OneToMany
private List castings;
Diğer
Örnek
Elimizde şöyle bir enum olsun.
public enum Areas {
  AREA_1, AREA_2
}
Şöyle yaparız.
@ElementCollection
@Column(name = "areas_interes", nullable = true)
@Enumerated(EnumType.STRING)
private List<Areas> areas_interes;
Örnek
Set ile kullanmak için şöyle yaparız.
@ElementCollection
@CollectionTable(name="user_page", joinColumns=@JoinColumn(name="id_user"))
@Column(name="id_page")
public Set<Long> pageIds;
Örnek
List ile kullanmak için şöyle yaparız.
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "variant_option_vals",
        joinColumns = @JoinColumn(name = "variantOption_id")
@OrderColumn(name="sequence")
)
private List<String> optionValues;
Örnek
Sanırım 3 katlı iç içe listelerde kullanılamıyor.
@ElementCollection
@CollectionTable(joinColumns = @JoinColumn(name = "id"))
@OrderBy("id")
private List<List<List<Double>>> coordinates

Hiç yorum yok:

Yorum Gönder