JPA 2.1 Entity Graph
Entity; veritabanı ile senkronizasyon halinde bulunan özel Java nesneleridir. Entity Graph ise, bir Entity nesnesinin sahip olduğu veri alanlarının veritabanından çekeceği verileri ne zaman çekeceği ile ilgili özel bir konudur. Entity Graph yapısı, JPA çekim stratejisini (fetch strategy) yapılandırmaya olanak sunan bir özelliktir.
Bir Entity nesnesinin sahip olduğu veriler, veritabanından elde edilirken 2 tip veri çekme stratejisi kullanılmaktadır. Bu tipler;
Geç yüklemeyi/ihtiyaç halinde yüklemeyi temsil eden LAZY ve anında yüklemeyi temsil eden EAGER‘dir.
JPA ortamında, temel tipler (int, double, boolean ..) ve onların sarmalayıcı tipleri (Integer, Double, Boolean ..) varsayılan olarak EAGER olarak yapılandırılmıştır. Yani veritabanı yönünden JPA yönüne, Entity nesneleri üzerinden veri talep edildiğinde, EAGER alanlar veritabanındaki değerleriyle derhal doldurulmaktadır.
JPA ortamındaki, temel tiplere göre daha büyük veri barındırma ihtimali olan alanlar ise (Collection, List, Set ..), varsayılan çekim stratejisi LAZY olarak yapılandırılmıştır. LAZY olarak yapılandırılan alanlar, verilerini talep edildiğinde değil, mevcut alanlar kullanıldığında veritabanından çekmektedir. Buradaki maksat ise, kompleks verilerin sadece ihtiyaç olduğunda veritabanından çekilerek, performansın artırılmasını amaçlamaktır.
JPA standardına göre yapılandırılan varsayılan LAZY ve EAGER çekim stratejileri, geliştirici tarafından değiştirilebilirdir. Örneğin aşağıda yer alan Takim Entity sınıfı, EAGER ve LAZY olması açısından tekrardan yapılandırılabilir.
Takim Sınıfı (Varsayılan):
Varsayılan çekim biçiminde temel tipler ve sarmalıyıcları EAGER, List oyuncular; alanı ise LAZY olarak değerlendirilmektedir.
@Entity
public class Takim {
@Id
private Long id; // EAGER
private String ad; // EAGER
private Integer kurulus; // EAGER
private String stad; // EAGER
private String baskan; // EAGER
@OneToMany
private List oyuncular; // LAZY
// getter ve setter metodlar
}
Takim Sınıfı (Özelleştirilmiş):
Özelleştirilmiş biçimde ise, varsayılan stratejileri notasyonlar ile düzenleyebilmekteyiz. Temel alanlar için @Basic, kompleks alanlar ve java.util.Collection türünden alanlar için ise @OneToMany, @ManyToMany, @OneToOne, @ManyToOne gibi notasyonların “fetch” alanları ile düzenleme yapılabilmektedir.
@Entity
public class Takim {
@Basic(fetch = FetchType.LAZY)
private String ad; // LAZY
@Basic(fetch = FetchType.LAZY)
private Integer kurulus; // LAZY
@Basic(fetch = FetchType.EAGER)
private String stad; // EAGER
private String baskan;
@OneToMany(fetch = FetchType.EAGER)
private List oyuncular; // EAGER
// getter ve setter metodlar
}
Entity Graph
Entity Graph yapısında ise, notasyonlar ile düzenlenebilen çekim (fetch) stratejilerini, geliştiricinin tanımlaması için alternatif bir yol sunmaktadır. Entity Graph’lar ile, işaretlenen alanlar EAGER olarak yapılandırılmakta, işaretlenmeyen alanlar ise LAZY olarak yapılandırılmaktadır.
Örneğin yukarıdaki Takim – Futbolcu Entity ilişkisinde “select t from Takim t” sorgusu işletildiğinde Takim sınıfının oyuncular alanı LAZY, diğer alanları ise EAGER olarak olarak veritabanından elde edilecektir. Fakat biz bu varsayılan özelliği Entity Graph’ lar ile istediğimiz gibi düzenleyebiliriz.
Örneğin;
Takim Entity sınıfında; ad ve stad alanları çekme stratejisi EAGER olsun,
Futbolcu sınıfında ise; ad ve numara alanları EAGER olsun, diğer kalan alanların çekim stratejisi de LAZY olsun isteyelim.
İşte bu gibi kompleks istekleri Entity Graphl’ lar ile gerçekleyebiliriz.
Entity Graph yapısı hem programatik hem de notasyon bazlı olarak kurulabilmektedir.
1. Programatik olarak
JPA 2.1 ile getirilen EntityManager#createEntityGraph metodu ile EntityGraph nesneleri oluşturulur. Bir JPA Hint olarak sorguya eklenerek sorgulama yapılır.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("graph-pu");
EntityManager em = emf.createEntityManager();
EntityGraph graph = em.createEntityGraph(Takim.class);
graph.addAttributeNodes("ad","stad");
graph.addSubgraph("oyuncular").addAttributeNodes("ad","numara");
TypedQuery query = em.createQuery("select t from Takim t", Takim.class);
query.setHint("javax.persistence.fetchgraph", graph); // Dikkat
List takimlar = query.getResultList();
2. Notasyon Bazlı
JPA NamedQuery yapısına benzer biçimde NamedEntityGraph notasyonu ile EGAER olarak çekilmesi istenen alanlar işaretlenmektedir. Kalan alanlar ise LAZY olarak yapılandırılmaktadır.
@Entity
@NamedEntityGraph(name = "takimGraph",
attributeNodes =
{
@NamedAttributeNode("ad"),
@NamedAttributeNode("stad"),
@NamedAttributeNode(value = "oyuncular", subgraph = "oyuncular")
},
subgraphs =
{
@NamedSubgraph(name = "oyuncular", attributeNodes = {
@NamedAttributeNode("ad"), @NamedAttributeNode("numara")
})
}
)
public class Takim {
@Id
private Long id;
private String ad;
private Integer kurulus;
private String stad;
private String baskan;
@OneToMany
private List oyuncular;
}
Yukarıda yer alan takimGraph isimli NamedEntityGraph buna bir örnek gösterilebilir.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("graph-pu");
EntityManager em = emf.createEntityManager();
EntityGraph graph = em.getEntityGraph("takimGraph"); // Dikkat
List takimlar = em.createQuery("select t from Takim t", Takim.class).setHint("javax.persistence.fetchgraph", graph).getResultList();
İsimlendirilmiş Graph elemanları EntityManager#getEntityGraph metodu ile de elde edilebilmektedir. Her iki biçimde de, kompleks çekim (fetch) strateji ihtiyaçları kurgulanabilmektedir.
Debug zamanı
Şimdi EntityGraph destekli olarak “select t from Takim t” sorgusu yapılandırıldığına göre [List takimler] alanını Debug ekranında irdeleyebiliriz. EAGER olarak yapılandırılan alanların değerlerinin var olduğunu, LAZY alanların ise henüz verileri veritabanından çekilmediği için NULL olduğunu görebiliriz.
Fakat bu alanların Debug ekranında Null olarak gözükmesi sizi yanıltmasın, gerçek değeri elbette Null olabilir fakat buradaki Null oluş sebebi, alana dair verinin veritabanından henüz çekilmemesidir.
Soru : Peki bu veriler ne zaman veritabanından çekilecek? Cevap: Alan ilk kullanıldığında veritabanından çekim işlemi yapılacaktır.
Tekrar görüşmek dileğiyle..