Eğer bir sorgu sonucu entity listesine karşılık gelmiyor ise yeni bir class yaratıp select sorgusunda bu class'ı kullanabilirsiniz. Örneğin select memberid,count(*) from message group by memberid gibi bir sorgu sonucu bir id ve bir sayıdan oluşan bir liste dönmektedir. Sonuç bir entity listesi olmadığı için aşağıdaki gibi bir class yaratabilirsiniz :
class MessageCount{
Long memberId;
Long count;
public MessageCount(Long memberId,Long count){
setMemberId(memberId);
setCount(count);
}
// set ve get aşağıda....
...
}
Ve select sorgusunu aşağıdaki gibi yazabilirsiniz :
select new MessageCount(m.memberid,count(m.memberid)) from Message m group by m.memberid;
Ve bu sorgu sonucunu aşağıdaki gibi alabilirsiniz :
String query="select new MessageCount(m.memberid,
count(m.memberid)) from Message m group by m.memberid;";
Query query=getEntityManager().createQuery(query);
List list=query.getResultList();
JSF bir data componentinin (datatable,repeater vb..) value alanına bir JPA entity'sinin Set tipinde bir özelliğini verirseniz aşağıdaki exception oluşur :
not found on type org.hibernate.collection.PersistentSet
Bu sorunu çözmek için data componentine (datatable,repeater vb..) Set yerine List tipi verilmelidir. Bunun için entity'ye aşağıdaki gibi bir fonksiyon eklenebilir :
@Transient
public List geXAsList() {
List list = new ArrayList(X);
return list;
}
Yukarıda X tipinde bir Set bulunduran entity'de List olarak döndüren method görülmektedir
Bir JPA projesinde Entity sınıflarınızda orta özellikler var ise (Örneğin yaratılma tarihi, id vb..) bu özellikleri her Entity class'ına ayrı olarak yazmak yerine super bir class'a yazabilirsiniz. Bunu yapmak için super class aşağıdaki gibi tanımlanmalıdır :
@MappedSuperclass
public class BaseEntity{
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "creation_date")
private Calendar creationDate;
}
Yukarıdaki örnekte yaratılma tarihi özelliği genel bir özellik gibi tanımlanmıştır. Aşağıda bu class'ı extend eden entity class'ı görülmektedir:
@Entity
public class Test extends BaseEntity {
@Column(name = "name")
private String name;
}
Yukarıda yaratılan Test entity class'ı için veritabanında tablo yaratıldığında hem name sütunu hem de creation_date sütunu olacaktır.
JPA'da Entity sınıflarını normal bir sınıftan (POJO sınıfı) türetebilirsiniz. Farklı entity class'larında ortak bazı özellikleri (veritabanı eşleştirme ile ilgili olmayan) normal bir java sınıfında toplayabilirsiniz. Aşağıdaki gibi yapı kurulabilmektedir :
public class EntityBase{
...
}
@Entity
public class Entity1 extend EntityBase{
}
@Entity
public class Entity2 extend EntityBase{
}
Generic bir sınıf yaptığınızda , generic verilen parametrenin sınıfına ihtiyacınız olabilir. Normal durumda metot içinde verilen parametrenin sınıfını bulamazsınız. Örneğin JPA için genel bir data access sınıfı aşağıdaki gibi olsun :
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
public class GenericDao<T,PK> {
private EntityManager entityManager;
public GenericDao() {
entityManager = Persistence.createEntityManagerFactory("TestJPA").createEntityManager();
}
public Test find(Long id) {
return entityManager.find(entityClass, id); // hata
}
public void create(Test t) {
entityManager.persist(t);
}
public void update(Test t) {
entityManager.merge(t);
}
public void delete(Test t) {
entityManager.remove(t);
}
}
Yukarıdaki kod derlenemez. entityManager.find(entityClass, id) satırında T'nin sınıfı gerekmektedir. Generic bir değişkenin sınıfını o anda alamazsınız. T'nin sınıfını almak için T sınıfı için kurucuda bir Class değişkeni yaratılabilir ve aşağıdaki gibi yaratılabilir :
import java.lang.reflect.ParameterizedType;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
public class GenericDao<T, PK> {
private EntityManager entityManager;
protected Class<T> entityClass;
public GenericDao() {
entityManager = Persistence.createEntityManagerFactory("TestJPA").createEntityManager();
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
}
public T find(Long id) {
return entityManager.find(entityClass, id); // hata
}
public void create(T t) {
entityManager.persist(t);
}
public void update(T t) {
entityManager.merge(t);
}
public void delete(T t) {
entityManager.remove(t);
}
}
Görüldüğü gibi kurucuda
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
ile T argümanın sınıfı tespit edilmiştir. Bu şekilde find metodunda kullanılabilir.
JPA ve Hibernate kullandığınız bir projeyi test veya production ortamına attığınız aşağıdaki gibi bir hata oluşabilir:
org.hibernate.boot.archive.spi.ArchiveException: Could not build ClassFile
at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassFile(ClassFileArchiveEntryHandler.java:64) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:47) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:152) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:47) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:75) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:98) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.(EntityManagerFactoryBuilderImpl.java:199) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.jpa.boot.spi.Bootstrap.getEntityManagerFactoryBuilder(Bootstrap.java:34) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilder(HibernatePersistenceProvider.java:165) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:114) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:71) ~[scheduler-0.0.1-SNAPSHOT.jar:?]
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:52) [scheduler-0.0.1-SNAPSHOT.jar:?]
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55) [scheduler-0.0.1-SNAPSHOT.jar:?]
..
javax.persistence.PersistenceException: Unable to build entity manager factory
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:66)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
..
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: org.hibernate.boot.archive.spi.ArchiveException: Could not build ClassFile
at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.toClassFile(ClassFileArchiveEntryHandler.java:64)
at org.hibernate.boot.archive.scan.spi.ClassFileArchiveEntryHandler.handleEntry(ClassFileArchiveEntryHandler.java:47)
at org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor.visitArchive(JarFileBasedArchiveDescriptor.java:152)
at org.hibernate.boot.archive.scan.spi.AbstractScannerImpl.scan(AbstractScannerImpl.java:47)
at org.hibernate.boot.model.process.internal.ScanningCoordinator.coordinateScan(ScanningCoordinator.java:75)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.prepare(MetadataBuildingProcess.java:98)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.(EntityManagerFactoryBuilderImpl.java:199)
at org.hibernate.jpa.boot.spi.Bootstrap.getEntityManagerFactoryBuilder(Bootstrap.java:34)
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilder(HibernatePersistenceProvider.java:165)
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:114)
at org.hibernate.jpa.HibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(HibernatePersistenceProvider.java:71)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:52)
bu hatayı çözmek için javassist projesinin son versiyonuna geçmeniz gerekebilir:
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
Bu işlemi yaptığınızda sorun büyük ihtimalle çözülecektir.