হাইবারনেট প্রক্সিটি কীভাবে একটি আসল সত্তা অবজেক্টে রূপান্তর করা যায়


161

হাইবারনেটের সময় Session , আমি কিছু বস্তু লোড করছি এবং কিছু কিছু অলস লোডিংয়ের কারণে প্রক্সি হিসাবে লোড করা হচ্ছে। সব ঠিক আছে এবং আমি অলস লোডিং বন্ধ করতে চাই না।

তবে পরে আরপিসির মাধ্যমে আমাকে কিছু বস্তু (আসলে একটি বস্তু) জিডাব্লুটি ক্লায়েন্টের কাছে প্রেরণ করতে হবে। এবং এটি ঘটে যে এই কংক্রিট অবজেক্টটি প্রক্সি is সুতরাং আমি এটি একটি সত্য বস্তুতে পরিণত করা প্রয়োজন। হাইবারনেটে আমি "ম্যাটারিয়ালাইজ" এর মতো কোনও পদ্ধতি খুঁজে পাচ্ছি না।

আমি কীভাবে কিছু বিষয়বস্তুকে তাদের শ্রেণি এবং আইডি জেনে প্রক্সি থেকে বাস্তবের দিকে পরিণত করতে পারি?

এই মুহুর্তে আমি দেখতে পাচ্ছি একমাত্র সমাধান হবার্নেটের ক্যাশে থেকে সেই জিনিসটি উচ্ছেদ করা এবং এটিকে পুনরায় লোড করা, তবে এটি বেশিরভাগ কারণেই সত্যই খারাপ।

উত্তর:


232

এখানে আমি একটি পদ্ধতি ব্যবহার করছি।

public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
        throw new 
           NullPointerException("Entity passed for initialization is null");
    }

    Hibernate.initialize(entity);
    if (entity instanceof HibernateProxy) {
        entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
                .getImplementation();
    }
    return entity;
}

1
আমি একই জিনিসটি করতে চেয়েছিলাম, সুতরাং আমি প্রজেক্ট উদাহরণটি একটি অবজেক্টআউটপুট স্ট্রিমে লিখেছিলাম এবং তারপরে এটি একটি সম্পর্কিত অবজেক্টআইপুট স্ট্রিম থেকে আবার পড়েছি এবং এটি দেখে মনে হয়েছে যে কৌশলটি করা হয়েছে। আমি নিশ্চিত না যে এটি একটি দক্ষ পদ্ধতির কিনা, তবে এখনও ভাবছি কেন এটি কাজ করেছে ... এ সম্পর্কে যে কোনও মন্তব্য প্রশংসিত হবে। ধন্যবাদ!
shrini1000

@ shrini1000 এটি কাজ করেছে কারণ সিরিয়ালকরণ করার সময় সংগ্রহটি আরম্ভ করা হয় (সেশনটি এখনও বন্ধ না হলে)। এছাড়াও HibernateProxyএকটি সংজ্ঞায়িত writeReplaceধারাবাহিকতাতে সময় বিশেষ কিছু করতে প্রয়োগকারীরা বলপূর্বক পদ্ধতি।
বোজহো

1
এটি করার জন্য কোনও পোর্টেবল (জেপিএ) উপায় আছে?
কাও

আমি যখন ফোন করি তখন কেন হাইবারনেট.ইনটিয়ালটি অলস ইনিটায়ালাইজ এক্সেক্সশনটি নিক্ষেপ করে? আমি কেবল এই জাতীয় ব্যবহার করছি: অবজেক্ট ও = সেশন.জেট (মাইক্লাস.ক্লাস, আইডি); অবজেক্ট অন্যান্য = o.getSomeOtherClass (); initializeAndUnproxy (অন্যান্য);
fredcrs

6
আপনি নিজের ব্যবহারের ক্লাস ছাড়াই এটি করতে পারেন -(T)Hibernate.unproxy(entity)
প্যানসর

46

আমি যেমন এই নিবন্ধে ব্যাখ্যা করেছি , যেহেতু হাইবারনেট ওআরএম 5.2.10 , আপনি এটি এর মতো করতে পারেন:

Object unproxiedEntity = Hibernate.unproxy(proxy);

হাইবারনেটের আগে 5.2.10 । এটি করার সহজতম উপায় হায়ারনেট অভ্যন্তরীণ PersistenceContextবাস্তবায়নের প্রস্তাবিত আনপ্রক্সি পদ্ধতিটি ব্যবহার করা ছিল :

Object unproxiedEntity = ((SessionImplementor) session)
                         .getPersistenceContext()
                         .unproxy(proxy);

এটি কি কোনও পিতামাতার সত্তাকে হ্যান্ডেল সংগ্রহের ক্ষেত্রগুলিতে কল করে ?? উদাহরণস্বরূপ, যদি আপনার Departmentতালিকার সাথে একটি থাকে তবে আপনার Studentএখনও কি দরকার unproxy(department.getStudents()) - বা এটি কি যথেষ্ট unproxy(department)?
ট্রাফালমডোরিয়ান

1
শুধুমাত্র প্রদত্ত প্রক্সি শুরু করা হয়েছে। এটি অ্যাসোসিয়েশনগুলিতে ক্যাসকেড করে না, কারণ এটি যদি আপনি কোনও মূল সত্তাকে আনপ্রক্সি করে থাকেন তবে সম্ভাব্যভাবে প্রচুর পরিমাণে ডেটা লোড করতে পারে।
ভ্লাদ মিহলসিয়া

তবে PersistentContext#unproxy(proxy)প্রক্সিটি অনির্বাচিত হয়ে থাকলে Hibernate.unproxy(proxy)এবং LazyInitializer#getImplementation(proxy)প্রয়োজনে প্রক্সি শুরু করার ক্ষেত্রে একটি ব্যতিক্রম ছুঁড়ে । এই পার্থক্যের কারণে কেবল একটি ব্যতিক্রম ধরা পড়ে। ;-)
বোগ্রাফ

13

ব্যবহার করার চেষ্টা করুন Hibernate.getClass(obj)


15
এটি ডিগ্রোক্সিড অবজেক্টের চেয়ে ক্লাসটি ফেরত দেয়
স্টিফান হাবেল

প্রকৃতপক্ষে এই সমাধানটি দুর্দান্ত হয় যখন আমরা উদাহরণের সাথে তুলনা করার জন্য ক্লাসের অবজেক্টটি সন্ধান করার চেষ্টা করি।
জোওও রেবেলো

13

আমি নিম্নলিখিত কোডগুলি লিখেছি যা প্রক্সিগুলি থেকে বস্তু পরিষ্কার করে (যদি তারা ইতিমধ্যে আরম্ভ না করা হয়)

public class PersistenceUtils {

    private static void cleanFromProxies(Object value, List<Object> handledObjects) {
        if ((value != null) && (!isProxy(value)) && !containsTotallyEqual(handledObjects, value)) {
            handledObjects.add(value);
            if (value instanceof Iterable) {
                for (Object item : (Iterable<?>) value) {
                    cleanFromProxies(item, handledObjects);
                }
            } else if (value.getClass().isArray()) {
                for (Object item : (Object[]) value) {
                    cleanFromProxies(item, handledObjects);
                }
            }
            BeanInfo beanInfo = null;
            try {
                beanInfo = Introspector.getBeanInfo(value.getClass());
            } catch (IntrospectionException e) {
                // LOGGER.warn(e.getMessage(), e);
            }
            if (beanInfo != null) {
                for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
                    try {
                        if ((property.getWriteMethod() != null) && (property.getReadMethod() != null)) {
                            Object fieldValue = property.getReadMethod().invoke(value);
                            if (isProxy(fieldValue)) {
                                fieldValue = unproxyObject(fieldValue);
                                property.getWriteMethod().invoke(value, fieldValue);
                            }
                            cleanFromProxies(fieldValue, handledObjects);
                        }
                    } catch (Exception e) {
                        // LOGGER.warn(e.getMessage(), e);
                    }
                }
            }
        }
    }

    public static <T> T cleanFromProxies(T value) {
        T result = unproxyObject(value);
        cleanFromProxies(result, new ArrayList<Object>());
        return result;
    }

    private static boolean containsTotallyEqual(Collection<?> collection, Object value) {
        if (CollectionUtils.isEmpty(collection)) {
            return false;
        }
        for (Object object : collection) {
            if (object == value) {
                return true;
            }
        }
        return false;
    }

    public static boolean isProxy(Object value) {
        if (value == null) {
            return false;
        }
        if ((value instanceof HibernateProxy) || (value instanceof PersistentCollection)) {
            return true;
        }
        return false;
    }

    private static Object unproxyHibernateProxy(HibernateProxy hibernateProxy) {
        Object result = hibernateProxy.writeReplace();
        if (!(result instanceof SerializableProxy)) {
            return result;
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private static <T> T unproxyObject(T object) {
        if (isProxy(object)) {
            if (object instanceof PersistentCollection) {
                PersistentCollection persistentCollection = (PersistentCollection) object;
                return (T) unproxyPersistentCollection(persistentCollection);
            } else if (object instanceof HibernateProxy) {
                HibernateProxy hibernateProxy = (HibernateProxy) object;
                return (T) unproxyHibernateProxy(hibernateProxy);
            } else {
                return null;
            }
        }
        return object;
    }

    private static Object unproxyPersistentCollection(PersistentCollection persistentCollection) {
        if (persistentCollection instanceof PersistentSet) {
            return unproxyPersistentSet((Map<?, ?>) persistentCollection.getStoredSnapshot());
        }
        return persistentCollection.getStoredSnapshot();
    }

    private static <T> Set<T> unproxyPersistentSet(Map<T, ?> persistenceSet) {
        return new LinkedHashSet<T>(persistenceSet.keySet());
    }

}

আমি আমার আরপিসি পরিষেবাদির (দিকগুলির মাধ্যমে) ফলাফলের উপরে এই ফাংশনটি ব্যবহার করি এবং এটি প্রক্সিগুলি থেকে পুনরুতরূপে সমস্ত ফলাফল অবজেক্টগুলিকে সাফ করে (যদি সেগুলি আরম্ভ না করা হয়)।


এই কোডটি ভাগ করে নেওয়ার জন্য ধন্যবাদ যদিও এটি সমস্ত ব্যবহারের ক্ষেত্রে আচ্ছাদন দেয় নি তবে এটি সত্যই সহায়ক ...
প্রেতিক সিং

সঠিক। এটি নতুন ক্ষেত্রে অনুসারে আপডেট করা উচিত। আপনি GWT ছেলেরা দ্বারা প্রস্তাবিত জিনিসগুলি চেষ্টা করতে পারেন। এখানে দেখুন: gwtproject.org/articles/used_gwt_with_hibernate.html (একীকরণ কৌশল অংশ দেখুন)। সাধারণভাবে তারা ডিটিও বা ডোজার বা গিলিয়েড ব্যবহার করার পরামর্শ দেয়। আপনি যদি এই বিষয়ে আপনার মতামত সরবরাহ করেন তবে ঠিক হবে। আমার ক্ষেত্রে এটি দেখে মনে হচ্ছে আমার কোডটি সহজ সমাধান, তবে পূর্ণ নয় = (
সের্গেয় বান্দারেভ

ধন্যবাদ। "কালেকশনস ইউটিলস.কন্টেনসটোটেলিএকুয়াল (হ্যান্ডলডঅবজেক্টস, মান)" এর জন্য আমরা একটি বাস্তবায়ন কোথায় পাব?
Ilan.K

পাবলিক স্ট্যাটিক বুলিয়ানতে রয়েছে টোটালিএকুয়াল (সংগ্রহ <?> সংগ্রহ, অবজেক্টের মান) {যদি (ইস্পটি (সংগ্রহ)) false মিথ্যা ফেরত দেয়; Ob এর জন্য (অবজেক্ট অবজেক্ট: সংগ্রহ) {যদি (অবজেক্ট == মান) {সত্য ফিরে আসে; false false মিথ্যা প্রত্যাবর্তন; }
সের্গে বোন্ডারেভ

এটি কেবল নিজের দ্বারা তৈরি ইউটিলিটি পদ্ধতি
সের্গে বোন্ডারেভ

10

আমি জেপিএ 2 এর সাথে যেভাবে পরামর্শ দিচ্ছি:

Object unproxied  = entityManager.unwrap(SessionImplementor.class).getPersistenceContext().unproxy(proxy);

2
আপনার উত্তর আমার চেয়ে আলাদা কীভাবে?
ভ্লাদ মিহলসিয়া

আমি এই সমাধানটি চেষ্টা করেছি ... আন-র্যাপ-কমান্ডের আগে আপনি যদি এমন কিছু না রাখেন তবে সর্বদা কাজ করে না: হাইবারনেটপ্রক্সি হাইবারনেটপ্রক্সি = (হাইবারনেটপ্রক্সি) সম্ভাব্য প্রক্সিঅবজেক্ট; যদি (হাইবারনেটপ্রক্সি.জিটহাইবারনেটলজিআইনিটিয়ালাইজার () .সইউনিটায়ালাইজড ()) {হাইবারনেটপ্রোসি.ইটহাইবারনেটলজিআইনিটিয়ালাইজার ()। আরম্ভ করুন (); }
ব্যবহারকারীর 22227576

2

স্প্রিং ডেটা জেপিএ এবং হাইবারনেট সহ, আমি এর সাব-ইন্টারফেস ব্যবহার করছিলাম JpaRepository "যোগদান" কৌশলটি ব্যবহার টাইপ শ্রেণিবদ্ধের সাথে সম্পর্কিত জিনিসগুলি । দুর্ভাগ্যক্রমে, অনুসন্ধানগুলি প্রত্যাশিত কংক্রিটের উদাহরণগুলির পরিবর্তে বেস টাইপের প্রক্সিগুলি ফিরিয়ে দিচ্ছিল। এটি আমাকে সঠিক ধরণের ফলাফল কাস্ট করতে বাধা দিয়েছে। আপনার মতো, আমি এখানে আমার এন্টিগুলি আনপ্রেসিড করার কার্যকর উপায় অনুসন্ধান করতে এসেছি।

ভ্লাদের এই ফলাফলগুলি সমুন্নত রাখার জন্য সঠিক ধারণা রয়েছে; ইন্নিস আরও কিছু বিশদ সরবরাহ করে। তাদের উত্তরে যুক্ত করা হচ্ছে, আপনি যা যা খুঁজছেন তা বাকিগুলি এখানে:

নিম্নলিখিত কোডটি আপনার প্রক্সিযুক্ত সত্তাকে আনপক্সি করার একটি সহজ উপায় সরবরাহ করে:

import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaContext;
import org.springframework.stereotype.Component;

@Component
public final class JpaHibernateUtil {

    private static JpaContext jpaContext;

    @Autowired
    JpaHibernateUtil(JpaContext jpaContext) {
        JpaHibernateUtil.jpaContext = jpaContext;
    }

    public static <Type> Type unproxy(Type proxied, Class<Type> type) {
        PersistenceContext persistenceContext =
            jpaContext
            .getEntityManagerByManagedType(type)
            .unwrap(SessionImplementor.class)
            .getPersistenceContext();
        Type unproxied = (Type) persistenceContext.unproxyAndReassociate(proxied);
        return unproxied;
    }

}

আপনি অপ্রক্সাইড এনটাইটস বা প্রক্সাইড সত্তাগুলি হয় পাস করতে পারেন unproxy । যদি তারা ইতিমধ্যে অনুপস্থিত থাকে তবে কেবল তাদের ফিরিয়ে দেওয়া হবে। অন্যথায়, তারা অযৌক্তিক হয়ে ফিরে আসবে।

আশাকরি এটা সাহায্য করবে!


1

আরেকটি কর্মসূচী কল করা হয়

Hibernate.initialize(extractedObject.getSubojbectToUnproxy());

অধিবেশন বন্ধ করার ঠিক আগে।


1

আমি স্ট্যান্ডার্ড জাভা এবং জেপিএ এপিআই ব্যবহার করে কোনও শ্রেণি ডিপ্রোক্সি করার সমাধান পেয়েছি। হাইবারনেট দ্বারা পরীক্ষিত, তবে নির্ভরতা হিসাবে হাইবারনেটের প্রয়োজন হয় না এবং সমস্ত জেপিএ সরবরাহকারীদের সাথে কাজ করা উচিত।

একমাত্র প্রয়োজনীয়তা - প্যারেন্ট ক্লাস (ঠিকানা) সংশোধন করা এবং একটি সহজ সহায়ক পদ্ধতি যুক্ত করা এটির প্রয়োজনীয়।

সাধারণ ধারণা: অভিভাবক শ্রেণিতে সহায়ক পদ্ধতি যুক্ত করুন যা নিজে ফিরে আসে itself যখন প্রক্সিটিতে পদ্ধতি কল করা হবে, এটি কলটিকে আসল দৃষ্টিতে ফরোয়ার্ড করবে এবং এই প্রকৃত উদাহরণটি ফিরে আসবে।

বাস্তবায়ন খানিকটা জটিল, কারণ হাইবারনেট স্বীকৃতি দেয় যে প্রক্সাইড শ্রেণি নিজেই ফিরে আসে এবং এখনও প্রকৃত উদাহরণের পরিবর্তে প্রক্সি প্রদান করে। ওয়ার্কআরাউন্ডটি হ'ল রিটার্নড ইনস্ট্যান্সকে একটি সাধারণ মোড়কের ক্লাসে মোড়ানো, যা প্রকৃত উদাহরণের চেয়ে পৃথক শ্রেণীর ধরণ।

কোডে:

class Address {
   public AddressWrapper getWrappedSelf() {
       return new AddressWrapper(this);
   }
...
}

class AddressWrapper {
    private Address wrappedAddress;
...
}

আসল সাবক্লাসে ঠিকানা প্রক্সি কাস্ট করতে, নিম্নলিখিত ব্যবহার করুন:

Address address = dao.getSomeAddress(...);
Address deproxiedAddress = address.getWrappedSelf().getWrappedAddress();
if (deproxiedAddress instanceof WorkAddress) {
WorkAddress workAddress = (WorkAddress)deproxiedAddress;
}

আপনার উদাহরণ কোডটি কিছুটা অস্পষ্ট বলে মনে হচ্ছে (অথবা সম্ভবত আমার আরও কফির প্রয়োজন আছে)। কোথা থেকে সত্তাওয়ালা আসে? এড্রেস র্যাপার হওয়া উচিত? এবং আমি অ্যাড্রেস র‌্যাপডকে অ্যাড্রেস র‌্যাপার বলতে হবে? আপনি এই পরিষ্কার করতে পারেন?
Gus

@ গুস, আপনি ঠিক বলেছেন। আমি উদাহরণ সংশোধন। ধন্যবাদ :)
ওনড্রোমিহ


0

প্রস্তাবিত সমাধানের জন্য আপনাকে ধন্যবাদ! দুর্ভাগ্যক্রমে, তাদের কেউই আমার মামলার পক্ষে কাজ করেনি: জেপিএ-এর মাধ্যমে হাইবারনেট-এর মাধ্যমে ওরাকল ডাটাবেস থেকে সিএলওবি অবজেক্টের একটি তালিকা প্রাপ্ত, একটি স্থানীয় কোয়েরি ব্যবহার করে।

প্রস্তাবিত সমস্ত পদ্ধতির আমাকে একটি ক্লাসকাস্টএক্সসেপশন দিয়েছে বা সবেমাত্র জাভা প্রক্সি অবজেক্টটি দিয়েছে (যার ভিতরে গভীরভাবে কাঙ্ক্ষিত ক্লোব রয়েছে)।

সুতরাং আমার সমাধানটি নিম্নলিখিত (উপরের কয়েকটি পদ্ধতির উপর ভিত্তি করে):

Query sqlQuery = manager.createNativeQuery(queryStr);
List resultList = sqlQuery.getResultList();
for ( Object resultProxy : resultList ) {
    String unproxiedClob = unproxyClob(resultProxy);
    if ( unproxiedClob != null ) {
       resultCollection.add(unproxiedClob);
    }
}

private String unproxyClob(Object proxy) {
    try {
        BeanInfo beanInfo = Introspector.getBeanInfo(proxy.getClass());
        for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
            Method readMethod = property.getReadMethod();
            if ( readMethod.getName().contains("getWrappedClob") ) {
                Object result = readMethod.invoke(proxy);
                return clobToString((Clob) result);
            }
        }
    }
    catch (InvocationTargetException | IntrospectionException | IllegalAccessException | SQLException | IOException e) {
        LOG.error("Unable to unproxy CLOB value.", e);
    }
    return null;
}

private String clobToString(Clob data) throws SQLException, IOException {
    StringBuilder sb = new StringBuilder();
    Reader reader = data.getCharacterStream();
    BufferedReader br = new BufferedReader(reader);

    String line;
    while( null != (line = br.readLine()) ) {
        sb.append(line);
    }
    br.close();

    return sb.toString();
}

আশা করি এটি কারও সাহায্য করবে!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.