मैं चयनित जवाब से असहमत हूं, और जैसा कि davidxxx ने ठीक से बताया है, getReference बिना चयन के गतिशील अपडेशन का ऐसा व्यवहार प्रदान नहीं करता है। मैंने इस उत्तर की वैधता के संबंध में एक प्रश्न पूछा, यहां देखें - हाइबरनेट JPA के getReference () के बाद सेटर का उपयोग किए बिना चयन जारी किए बिना अपडेट नहीं किया जा सकता है ।
मैंने बहुत ईमानदारी से किसी को भी नहीं देखा है जो वास्तव में उस कार्यक्षमता का उपयोग करता है। कहीं भी। और मुझे समझ नहीं आ रहा है कि यह इतना उलझा हुआ क्यों है।
अब सबसे पहले, कोई फर्क नहीं पड़ता कि आप हाइबरनेट प्रॉक्सी ऑब्जेक्ट, सेटर या गेट्टर पर कॉल करते हैं, एक SQL निकाल दिया जाता है और ऑब्जेक्ट लोड हो जाता है।
लेकिन फिर मैंने सोचा, तो क्या होगा अगर JPA getReference () प्रॉक्सी उस कार्यक्षमता को प्रदान नहीं करता है। मैं सिर्फ अपना प्रॉक्सी लिख सकता हूं।
अब, हम सभी यह तर्क दे सकते हैं कि प्राथमिक कुंजियों पर चयन उतनी ही तेजी से होता है जितना एक क्वेरी प्राप्त कर सकता है और इससे बचने के लिए वास्तव में महान लंबाई पर जाना कुछ नहीं है। लेकिन हम में से जो एक कारण या किसी अन्य के कारण इसे संभाल नहीं सकते हैं, नीचे ऐसे प्रॉक्सी का कार्यान्वयन है। लेकिन इससे पहले कि आप कार्यान्वयन देखें, यह देखें कि यह उपयोग है और इसका उपयोग कितना सरल है।
उपयोग
Order example = ProxyHandler.getReference(Order.class, 3);
example.setType("ABCD");
example.setCost(10);
PersistenceService.save(example);
और यह निम्नलिखित प्रश्न को आग देगा -
UPDATE Order SET type = 'ABCD' and cost = 10 WHERE id = 3;
और यदि आप सम्मिलित करना चाहते हैं, तब भी आप PersistenceService.save (नया आदेश ("a", 2)) कर सकते हैं; और यह एक डालने के रूप में यह चाहिए आग होगा।
कार्यान्वयन
इसे अपने pom.xml में जोड़ें -
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
गतिशील प्रॉक्सी बनाने के लिए इस वर्ग को बनाएं -
@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());
}
}
सभी विधियों के साथ एक इंटरफ़ेस बनाएं -
public interface EnhancedProxy {
public String getJPQLUpdate();
public HashMap<String, Object> getModifiedFields();
}
अब, एक इंटरसेप्टर बनाएं जो आपको इन तरीकों को अपने प्रॉक्सी पर लागू करने की अनुमति देगा -
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!");
}
}
और अपवाद वर्ग -
public class ProxyInstantiationException extends RuntimeException {
public ProxyInstantiationException(String message) {
super(message);
}
इस प्रॉक्सी का उपयोग करके सेव करने की सेवा -
@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);
}
}
}