Seçili yanıta katılmıyorum ve davidxxx'in doğru bir şekilde işaret ettiği gibi, getReference, seçme olmadan dinamik güncellemelerin bu tür davranışını sağlamaz. Bu cevabın geçerliliğiyle ilgili bir soru sordum, buraya bakın - hazırda bekletme JPA'sının getReference () 'sinden sonra setter'ı kullanarak select'i yayınlamadan güncelleme yapılamaz .
Dürüst olmak gerekirse, bu işlevi gerçekten kullanan kimseyi görmedim. HERHANGİ BİR YER. Ve neden bu kadar olumlu oy verildiğini anlamıyorum.
Şimdi her şeyden önce, bir hazırda bekletme proxy nesnesinde, bir ayarlayıcıda veya alıcıda ne çağırırsanız çağırın, bir SQL çalıştırılır ve nesne yüklenir.
Ama sonra düşündüm, peki ya JPA getReference () proxy'si bu işlevi sağlamazsa. Sadece kendi vekilimi yazabilirim.
Şimdi, birincil anahtarlarda seçimlerin bir sorgunun alabileceği kadar hızlı olduğunu ve gerçekten kaçınılması gereken çok uzun sürmesi gereken bir şey olmadığını iddia edebiliriz. Ancak, şu ya da bu nedenle bunu kaldıramayanlarımız için, aşağıda böyle bir vekilin uygulaması var. Ancak uygulamayı görmeden önce, kullanımını ve kullanımının ne kadar basit olduğunu görün.
KULLANIM
Order example = ProxyHandler.getReference(Order.class, 3);
example.setType("ABCD");
example.setCost(10);
PersistenceService.save(example);
Ve bu, aşağıdaki sorguyu tetikler -
UPDATE Order SET type = 'ABCD' and cost = 10 WHERE id = 3;
ve eklemek isteseniz bile, PersistenceService.save (new Order ("a", 2)) yapabilirsiniz; ve olması gerektiği gibi bir eki ateşler.
UYGULAMA
Bunu pom.xml dosyanıza ekleyin -
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
Bu sınıfı dinamik proxy oluşturacak şekilde yapın -
@SuppressWarnings("unchecked")
public class ProxyHandler {
public static <T> T getReference(Class<T> classType, Object id) {
if (!classType.isAnnotationPresent(Entity.class)) {
throw new ProxyInstantiationException("This is not an entity!");
}
try {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(classType);
enhancer.setCallback(new ProxyMethodInterceptor(classType, id));
enhancer.setInterfaces((new Class<?>[]{EnhancedProxy.class}));
return (T) enhancer.create();
} catch (Exception e) {
throw new ProxyInstantiationException("Error creating proxy, cause :" + e.getCause());
}
}
Tüm yöntemlerle bir arayüz oluşturun -
public interface EnhancedProxy {
public String getJPQLUpdate();
public HashMap<String, Object> getModifiedFields();
}
Şimdi, bu yöntemleri proxy'nize uygulamanıza izin verecek bir engelleyici yapın -
import com.anil.app.exception.ProxyInstantiationException;
import javafx.util.Pair;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import javax.persistence.Id;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
/**
* @author Anil Kumar
*/
public class ProxyMethodInterceptor implements MethodInterceptor, EnhancedProxy {
private Object target;
private Object proxy;
private Class classType;
private Pair<String, Object> primaryKey;
private static HashSet<String> enhancedMethods;
ProxyMethodInterceptor(Class classType, Object id) throws IllegalAccessException, InstantiationException {
this.classType = classType;
this.target = classType.newInstance();
this.primaryKey = new Pair<>(getPrimaryKeyField().getName(), id);
}
static {
enhancedMethods = new HashSet<>();
for (Method method : EnhancedProxy.class.getDeclaredMethods()) {
enhancedMethods.add(method.getName());
}
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//intercept enhanced methods
if (enhancedMethods.contains(method.getName())) {
this.proxy = obj;
return method.invoke(this, args);
}
//else invoke super class method
else
return proxy.invokeSuper(obj, args);
}
@Override
public HashMap<String, Object> getModifiedFields() {
HashMap<String, Object> modifiedFields = new HashMap<>();
try {
for (Field field : classType.getDeclaredFields()) {
field.setAccessible(true);
Object initialValue = field.get(target);
Object finalValue = field.get(proxy);
//put if modified
if (!Objects.equals(initialValue, finalValue)) {
modifiedFields.put(field.getName(), finalValue);
}
}
} catch (Exception e) {
return null;
}
return modifiedFields;
}
@Override
public String getJPQLUpdate() {
HashMap<String, Object> modifiedFields = getModifiedFields();
if (modifiedFields == null || modifiedFields.isEmpty()) {
return null;
}
StringBuilder fieldsToSet = new StringBuilder();
for (String field : modifiedFields.keySet()) {
fieldsToSet.append(field).append(" = :").append(field).append(" and ");
}
fieldsToSet.setLength(fieldsToSet.length() - 4);
return "UPDATE "
+ classType.getSimpleName()
+ " SET "
+ fieldsToSet
+ "WHERE "
+ primaryKey.getKey() + " = " + primaryKey.getValue();
}
private Field getPrimaryKeyField() throws ProxyInstantiationException {
for (Field field : classType.getDeclaredFields()) {
field.setAccessible(true);
if (field.isAnnotationPresent(Id.class))
return field;
}
throw new ProxyInstantiationException("Entity class doesn't have a primary key!");
}
}
Ve istisna sınıfı -
public class ProxyInstantiationException extends RuntimeException {
public ProxyInstantiationException(String message) {
super(message);
}
Bu proxy kullanılarak kaydedilecek bir hizmet -
@Service
public class PersistenceService {
@PersistenceContext
private EntityManager em;
@Transactional
private void save(Object entity) {
// update entity for proxies
if (entity instanceof EnhancedProxy) {
EnhancedProxy proxy = (EnhancedProxy) entity;
Query updateQuery = em.createQuery(proxy.getJPQLUpdate());
for (Entry<String, Object> entry : proxy.getModifiedFields().entrySet()) {
updateQuery.setParameter(entry.getKey(), entry.getValue());
}
updateQuery.executeUpdate();
// insert otherwise
} else {
em.persist(entity);
}
}
}