কীভাবে একটি স্প্রিং কন্ট্রোলারে জেপিএ এবং হাইবারনেটের সাথে ফেচটাইপ.লাজি সংঘবদ্ধতা আনতে হয়


146

আমার এক ব্যক্তি শ্রেণি রয়েছে:

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany(fetch = FetchType.LAZY)
    private List<Role> roles;
    // etc
}

একাধিক থেকে বহু সম্পর্কের সাথে যা অলস।

আমার নিয়ামক আমি

@Controller
@RequestMapping("/person")
public class PersonController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping("/get")
    public @ResponseBody Person getPerson() {
        Person person = personRepository.findOne(1L);
        return person;
    }
}

এবং পার্সনরোপোসিটরিটি কেবল এই কোড, এই গাইড অনুসারে লেখা

public interface PersonRepository extends JpaRepository<Person, Long> {
}

তবে এই নিয়ামকটিতে আমার আসলে অলস-ডেটা দরকার। আমি কীভাবে এর লোডিং ট্রিগার করতে পারি?

এটি অ্যাক্সেস করার চেষ্টা করা ব্যর্থ হবে

অলসভাবে ভূমিকা একটি সংগ্রহ আরম্ভ করতে ব্যর্থ: no.dusken.momus.model.Person.roles, প্রক্সি আরম্ভ করতে পারেনি - কোন সেশন নেই

বা আমি যা চেষ্টা করি তার উপর নির্ভর করে অন্যান্য ব্যতিক্রমগুলি।

আমার এক্সএমএল-বিবরণ , প্রয়োজনে।

ধন্যবাদ।


আপনি কি কোনও পদ্ধতি লিখতে পারেন, যা Personকিছু পরামিতি প্রদত্ত কোনও অবজেক্ট আনতে কোয়েরি তৈরি করবে ? এর মধ্যে Query, এই fetchধারাটি অন্তর্ভুক্ত করুন এবং Rolesব্যক্তির জন্য খুব লোড করুন ।
সুডোরাহুল

উত্তর:


206

এটি শুরু করার জন্য আপনাকে অলস সংগ্রহের একটি স্পষ্ট কল করতে হবে (সাধারণ অভ্যাসটি .size()এই উদ্দেশ্যে কল করা)। হাইবারনেটে এই ( Hibernate.initialize()) এর জন্য একটি উত্সর্গীকৃত পদ্ধতি রয়েছে তবে জেপিএর সাথে এর সমতুল্য নেই। অবশ্যই আপনাকে নিশ্চিত করতে হবে যে অনুরোধটি সম্পন্ন হয়েছে, যখন সেশনটি এখনও পাওয়া যায়, তাই আপনার কন্ট্রোলার পদ্ধতিটি দিয়ে এটিকে বর্নিত করুন @Transactional। বিকল্পটি হ'ল কন্ট্রোলার এবং রিপোজিটরির মধ্যে একটি মধ্যবর্তী পরিষেবা স্তর তৈরি করা যা অলস সংগ্রহের সূচনা করে এমন পদ্ধতিগুলি প্রকাশ করতে পারে।

হালনাগাদ:

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

public interface PersonRepository extends JpaRepository<Person, Long> {

    @Query("SELECT p FROM Person p JOIN FETCH p.roles WHERE p.id = (:id)")
    public Person findByIdAndFetchRolesEagerly(@Param("id") Long id);

}

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


3
দয়া করে নোট করুন যে এটি একটি সহজ সমাধান, তবে ফলাফল ডাটাবেসের দুটি পৃথক প্রশ্নের জন্য (ব্যবহারকারীর জন্য একটি, এর ভূমিকার জন্য অন্য একটি)। আপনি যদি আরও ভাল পারফরম্যান্স অর্জন করতে চান, এমন উত্সর্গীকৃত পদ্ধতি লেখার চেষ্টা করুন যা উত্সাহিতভাবে ব্যবহারকারী এবং এর সাথে সম্পর্কিত ভূমিকাগুলি একক পদক্ষেপে জেপিকিউএল বা অন্যের পরামর্শ অনুসারে ক্রিটারিয়া এপিআই ব্যবহার করে নিয়ে আসে।
zagyi

আমি এখন জোসের উত্তরের উদাহরণ চেয়েছিলাম, স্বীকার করতে হবে আমি পুরোটা বুঝতে পারি না।
ম্যাটসেম্যান

আমার আপডেট করা উত্তরে কাঙ্ক্ষিত ক্যোয়ারী পদ্ধতির জন্য একটি সম্ভাব্য সমাধান পরীক্ষা করুন।
zagyi

7
মজার বিষয় লক্ষণীয়, আপনি যদি এগুলি joinনা করে থাকেন fetchতবে সেটটি ফিরে আসবে initialized = false; সেটটি একবার অ্যাক্সেস হয়ে যাওয়ার পরে এখনও একটি দ্বিতীয় ক্যোয়ারী জারি করুন। fetchসম্পর্কটি পুরোপুরি লোড হয়েছে এবং দ্বিতীয় ক্যোয়ারী এড়ানো নিশ্চিত করার মূল চাবিকাঠি।
FGreg

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

37

যদিও এটি একটি পুরানো পোস্ট, দয়া করে @ নেমেডেনিটিগ্রাফ (জাভাক্স পার্সিস্টেনস) এবং @ এন্টিটি গ্রাফ (স্প্রিং ডেটা জেপিএ) ব্যবহার করুন। সমন্বয় কাজ করে।

উদাহরণ

@Entity
@Table(name = "Employee", schema = "dbo", catalog = "ARCHO")
@NamedEntityGraph(name = "employeeAuthorities",
            attributeNodes = @NamedAttributeNode("employeeGroups"))
public class EmployeeEntity implements Serializable, UserDetails {
// your props
}

এবং তারপরে নীচে হিসাবে বসন্ত রেপো

@RepositoryRestResource(collectionResourceRel = "Employee", path = "Employee")
public interface IEmployeeRepository extends PagingAndSortingRepository<EmployeeEntity, String>           {

    @EntityGraph(value = "employeeAuthorities", type = EntityGraphType.LOAD)
    EmployeeEntity getByUsername(String userName);

}

1
নোটটি @NamedEntityGraphজেপিএ ২.১ এপিআই-র একটি অংশ, যা হাইবারনেটে ৪.৩.০ সংস্করণের আগে প্রয়োগ করা হয়নি।
নেক্সা

2
@EntityGraph(attributePaths = "employeeGroups")@NamedEntityGraphআপনার @Entity- এর কোনও প্রয়োজন ছাড়াই কোনও পদ্ধতিতে টীকা দেওয়ার জন্য সরাসরি একটি স্প্রিং ডেটা রিপোজিটরিতে ব্যবহার করা যেতে পারে - কম কোড, আপনি রেপো খুললে বুঝতে সহজ।
দেশীস্লাভ কামেনভ

13

আপনার কাছে কিছু বিকল্প আছে

  • সংগ্রহস্থল সম্পর্কিত একটি পদ্ধতি লিখুন যা আরজে প্রস্তাবিত হিসাবে একটি প্রাথমিক সত্তা ফিরিয়ে দেয়।

আরও কাজ, সেরা পারফরম্যান্স।

  • সম্পূর্ণ অনুরোধের জন্য সেশনটি উন্মুক্ত রাখতে ওপেনএটিটিম্যানেজারআইনভিউফিল্টারটি ব্যবহার করুন।

কম পরিশ্রম, সাধারণত ওয়েব পরিবেশে গ্রহণযোগ্য।

  • যখন প্রয়োজন হয় সত্তা শুরু করতে একটি সহায়ক বর্গ ব্যবহার করুন।

কম কাজ, কার্যকর যখন ওএমআইআইভি বিকল্প না হয়, উদাহরণস্বরূপ একটি দোল অ্যাপ্লিকেশনটিতে, তবে কোনও শটে কোনও সত্তা সূচনা করতে रिपॉিজিটরি বাস্তবায়নেও এটি কার্যকর হতে পারে।

শেষ বিকল্পের জন্য, আমি একটি ইউটিলিটি ক্লাস লিখেছিলাম, জেপাউটিলস কিছু deph এ সত্ত্বা initilize করতে।

উদাহরণ স্বরূপ:

@Transactional
public class RepositoryHelper {

    @PersistenceContext
    private EntityManager em;

    public void intialize(Object entity, int depth) {
        JpaUtils.initialize(em, entity, depth);
    }
}

যেহেতু আমার সমস্ত অনুরোধগুলি সরল আরএসএস কলগুলি কোনও রেন্ডারিং ইত্যাদি নেই তাই লেনদেনটি মূলত আমার সম্পূর্ণ অনুরোধ। আপনার ইনপুট জন্য ধন্যবাদ।
Matsemann

আমি প্রথমটি কীভাবে করব? আমি কীভাবে কোনও ক্যোয়ারী লিখতে জানি, তবে কী বলবে তা কীভাবে করা যায় তা নয়। আপনি একটি উদাহরণ দেখাতে পারেন? খুব সহায়ক হবে।
ম্যাটসেম্যান

যদিও জাগি তার উত্তরে একটি উদাহরণ দিয়েছেন, যাইহোক যাইহোক, আমাকে সঠিক দিকে নির্দেশ করার জন্য ধন্যবাদ।
ম্যাটসেম্যান

আমি জানি না কিভাবে আপনার ক্লাস বলা হবে! সমাধান সম্পূর্ণ না হয়ে অন্যের সময় নষ্ট করে
শায়দি শেরিফ

সম্পূর্ণ অনুরোধের জন্য সেশনটি উন্মুক্ত রাখতে ওপেনসেন্টি ম্যানেজারআইএনভিউ ফিল্টার ব্যবহার করুন - খারাপ ধারণা। আমি আমার সত্তাগুলির জন্য সমস্ত সংগ্রহ আনার জন্য একটি অতিরিক্ত অনুরোধ করব।
ইয়ান খোন্সকি

8

কোনও লেনদেনের মধ্যেই এটি অলসভাবে লোড করা যায়। সুতরাং আপনি আপনার সংগ্রহস্থলের সংগ্রহটি অ্যাক্সেস করতে পারেন, যার একটি লেনদেন রয়েছে - বা আমি সাধারণত যা করি তা হ'ল একটি get with association, বা উত্সাহী হিসাবে ফ্যাচমোড সেট করুন।


6

আমার মনে হয় ভিউ রেন্ডারিংয়ের সময় আপনার সেশনটি উন্মুক্ত রাখতে আপনার ওপেনসেশনআইনভিউ ফিল্টার প্রয়োজন (তবে এটি খুব ভাল অনুশীলন নয়)।


1
যেহেতু আমি জেএসপি বা কিছু ব্যবহার করছি না, কেবলমাত্র একটি আরএসটি-এপিই তৈরি করছি, @ ট্রানজেকশনাল আমার পক্ষে তা করবে। তবে অন্যান্য সময়ে কাজে লাগবে। ধন্যবাদ।
ম্যাটসেম্যান

@ ম্যাটসেম্যান আমি জানি এখন অনেক দেরি হয়ে গেছে ... তবে আপনি কন্ট্রোলারে এমনকি ওপেনসেশনআইভিউ ফিল্টার ব্যবহার করতে পারবেন পাশাপাশি কোনও প্রতিক্রিয়া সংকলন না হওয়া পর্যন্ত সেশনটি উপস্থিত থাকবে ...
বিশ্বাস শশীধর

@ ম্যাটসেম্যান ধন্যবাদ! লেনদেন-টীকাটি আমার জন্য কৌশলটি করেছিল! fyi: এমনকি যদি আপনি কেবলমাত্র একটি বাকী-শ্রেণীর সুপারক্লাসটি বর্ননা করেন তবে এটি কাজ করে।
হতাশ

3

স্প্রিং ডেটা JpaRepository

স্প্রিং ডেটা JpaRepositoryনিম্নলিখিত দুটি পদ্ধতির সংজ্ঞা দেয়:

তবে আপনার ক্ষেত্রে, আপনি ফোন করেননি getOneবা findById:

Person person = personRepository.findOne(1L);

সুতরাং, আমি ধরে নিই যে findOneপদ্ধতিটি আপনি সেই পদ্ধতিতে সংজ্ঞায়িত করেছেন PersonRepository। তবে findOneপদ্ধতিটি আপনার ক্ষেত্রে খুব বেশি কার্যকর নয়। যেহেতু আপনার সংগ্রহের সাথে Personবরাবর আনতে হবে তাই rolesএটি ব্যবহার করা ভালfindOneWithRoles পরিবর্তে পদ্ধতি ।

কাস্টম স্প্রিং ডেটা পদ্ধতি

আপনি PersonRepositoryCustomনিম্নলিখিত হিসাবে একটি ইন্টারফেস সংজ্ঞায়িত করতে পারেন :

public interface PersonRepository
    extends JpaRepository<Person, Long>, PersonRepositoryCustom { 

}

public interface PersonRepositoryCustom {
    Person findOneWithRoles(Long id);
}

এবং এর বাস্তবায়নটিকে এভাবে परिभाषित করুন:

public class PersonRepositoryImpl implements PersonRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Person findOneWithRoles(Long id)() {
        return entityManager.createQuery("""
            select p 
            from Person p
            left join fetch p.roles
            where p.id = :id 
            """, Person.class)
        .setParameter("id", id)
        .getSingleResult();
    }
}

এটাই!


আপনি নিজের নিজের ক্যোয়ারীটি লিখেছেন এবং @ ক্রপান উত্তরে সত্ত্বা গ্রাফের মতো সমাধান ব্যবহার না করার কোনও কারণ আছে কি? এটি কি একই ফলাফল তৈরি করবে না?
জেরোইন ভ্যান্ডেভেল্ডে

সত্তাগ্রাফ ব্যবহারের জন্য ওভারহেড একটি জেপিকিউএল কোয়েরির চেয়ে বেশি। দীর্ঘমেয়াদে, আপনি কোয়েরিটি লেখার চেয়ে আরও ভাল।
ভ্লাদ মিহালসিয়া

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

1
কারণ এনটিটিগ্রাফের পরিকল্পনাগুলি জেপিকিউএলের মতো ক্যাশে হয় না। এটি একটি উল্লেখযোগ্য পারফরম্যান্স হিট হতে পারে।
ভ্লাদ মিহালসিয়া

1
যথাযথভাবে। আমার কিছুটা সময় লাগলে এটি সম্পর্কে একটি নিবন্ধ লিখতে হবে।
ভ্লাদ মিহালসিয়া

1

আপনি এটির মতো একই কাজটি করতে পারেন:

@Override
public FaqQuestions getFaqQuestionById(Long questionId) {
    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    FaqQuestions faqQuestions = null;
    try {
        faqQuestions = (FaqQuestions) session.get(FaqQuestions.class,
                questionId);
        Hibernate.initialize(faqQuestions.getFaqAnswers());

        tx.commit();
        faqQuestions.getFaqAnswers().size();
    } finally {
        session.close();
    }
    return faqQuestions;
}

কেবলমাত্র আপনার নিয়ামককে জিজ্ঞাসা করুন FAXQuestions.getFaqAnswers ()। আকার () এবং আপনি নিজেই তালিকাটি আনয়ন না করে অলসভাবে ইনটিলাইজড তালিকায় থাকলে আকারটি পাবেন।

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