সমস্যার বর্ণনা
যেমনটি আমরা উপরে বলেছি, LazyCollectionOption.EXTRA টীকাটিতে একটি সমস্যা আছে - এটি প্রতিটি বস্তুর জন্য ডাটাবেসের জন্য একটি পৃথক অনুরোধ করে। আমাদের হাইবারনেটকে কোনোভাবে ব্যাখ্যা করতে হবে যে আমরা চাই যে এটি অবিলম্বে আমাদের মূল বস্তুর জন্য সমস্ত চাইল্ড অবজেক্ট লোড করুক।
হাইবারনেটের বিকাশকারীরা এই সমস্যার সমাধান নিয়ে এসেছেন, HQL-এ জয়েন ফেচ অপারেটর।
HQL ক্যোয়ারী উদাহরণ:
select distinct task from Task t left join fetch t.employee order by t.deadline
এই প্রশ্নে, সবকিছু একই সময়ে সহজ এবং জটিল। আসুন এটি টুকরো টুকরো করে তৈরি করার চেষ্টা করি।
বিকল্প 1
আমরা সব অবজেক্ট ডাউনলোড করতে চাইটাস্ক, সময়সীমা অনুসারে সাজানো। এই অনুরোধটি দেখতে কেমন হবে:
select task from Task t order by t.deadline
যদিও সবকিছু পরিষ্কার। কিন্তু মাঠকর্মচারীটাস্ক ক্লাসে অতিরিক্ত টীকা সহ কর্মচারীদের একটি সংগ্রহ থাকবে । এবং এই সংগ্রহের বস্তু লোড করা হবে না.
বিকল্প 2
একটি বস্তুর জন্য চাইল্ড অবজেক্ট লোড করতে হাইবারনেটকে বাধ্য করুনটাস্ক.
select task from Task t join fetch t.employee order by t.deadline
সাহায্যের মাধ্যমে, আমরা আমাদের প্রশ্নের মধ্যে টাস্ক এবং কর্মচারী সত্তাকে স্পষ্টভাবে আবদ্ধ করি। হাইবারনেট ইতিমধ্যেই এটি জানে কারণ আমরা এই ক্ষেত্রগুলিতে @ManyToMany টীকা ব্যবহার করি।
কিন্তু আমাদের একটি যোগদানের বিবৃতি প্রয়োজন একটি যোগদানের বিবৃতি দিয়ে এটি সম্পূর্ণ করার জন্য একটি যোগদান আনার জন্য । এইভাবে আমরা হাইবারনেটকে বলি যে Task.employee সংগ্রহের বস্তুগুলিকে ডাটাবেস থেকে লোড করতে হবে যখন আমাদের অনুরোধটি কার্যকর করা হয়।
বিকল্প 3
পূর্ববর্তী সমাধানটিতে কয়েকটি বাগ রয়েছে। প্রথমত, জয়েন ব্যবহার করার পর, এসকিউএল আমাদের কাছে বস্তু ফেরত দেবে নাটাস্ক, যা কর্মচারী টেবিলে তাদের সাথে সম্পর্কিত কোন বস্তু নেই। ঠিক এভাবেই অভ্যন্তরীণ যোগদান কাজ করে ।
তাই আমাদের একটি বাম অপারেটরের সাথে আমাদের যোগদান বৃদ্ধি করতে হবে এবং এটিকে একটি বাম যোগদানে পরিণত করতে হবে । উদাহরণ:
select task from Task t left join fetch t.employee order by t.deadline
বিকল্প 4
কিন্তু এখানেই শেষ নয়. যদি আপনার কোডে সত্তার মধ্যে সম্পর্ক মেন-টু-মে হয়, তাহলে ক্যোয়ারী ফলাফলে ডুপ্লিকেট থাকবে। একই বস্তুটাস্কবিভিন্ন কর্মচারী (কর্মচারী বস্তু) পাওয়া যাবে.
তাই ডুপ্লিকেট টাস্ক অবজেক্ট থেকে মুক্তি পেতে আপনাকে সিলেক্ট ওয়ার্ডের পরে আলাদা কীওয়ার্ড যোগ করতে হবে।
select distinct task from Task t left join fetch t.employee order by t.deadline
এইভাবে 4টি ধাপে আমরা সেই অনুরোধে এসেছি যা দিয়ে আমরা শুরু করেছি। ঠিক আছে, জাভা কোডটি বেশ প্রত্যাশিত দেখাবে:
String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
return query.list();
যোগ দিন FETCH সীমাবদ্ধতা
কেউই নিখুঁত নয়। যোগান FETCH বিবৃতি এছাড়াও. এর বেশ কয়েকটি সীমাবদ্ধতা রয়েছে। এবং প্রথমটি setMaxResults() এবং setFirstResult() পদ্ধতি ব্যবহার করছে ।
JOIN FETCH স্টেটমেন্টের জন্য, আমাদের হাইবারনেট একটি খুব জটিল প্রশ্ন তৈরি করবে যেখানে আমরা তিনটি টেবিলকে একটিতে একত্রিত করব: কর্মচারী, টাস্ক এবং কর্মচারী_টাস্ক। প্রকৃতপক্ষে, এটি কর্মচারী বা কাজের জন্য একটি অনুরোধ নয়, তবে সমস্ত পরিচিত কর্মচারী-টাস্ক জোড়ার জন্য।
এবং এসকিউএল তার সীমা এবং অফসেট বিবৃতি প্রয়োগ করতে পারে কর্মচারী-টাস্ক জোড়ার ঠিক সেই প্রশ্নের জন্য। একই সময়ে, এটি HQL ক্যোয়ারী থেকে স্পষ্টভাবে অনুসরণ করে যে আমরা ঠিক কাজগুলি (টাস্ক) পেতে চাই এবং যদি আমরা আমাদের FirstResult এবং MaxResult পরামিতিগুলি পুনরায় বিতরণ করি, তাহলে তাদের বিশেষভাবে টাস্ক অবজেক্টগুলিতে উল্লেখ করা উচিত।
আপনি যদি এই মত কোড লিখুন:
String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
query.setFirstResult(0);
query.setMaxResults(1);
return query.list();
তারপর হাইবারনেট সঠিকভাবে FirstResult এবং MaxResult কে SQL কোয়েরির অফসেট এবং LIMIT প্যারামিটারে রূপান্তর করতে সক্ষম হবে না।
পরিবর্তে, এটি তিনটি জিনিস করবে:
- SQL ক্যোয়ারী সাধারণত টেবিল থেকে সমস্ত ডেটা নির্বাচন করবে এবং হাইবারনেটে ফিরিয়ে দেবে
- হাইবারনেট তার স্মৃতিতে প্রয়োজনীয় রেকর্ডগুলি নির্বাচন করবে এবং সেগুলি আপনাকে ফেরত দেবে
- হাইবারনেট একটি সতর্কতা জারি করবে
সতর্কতাটি এরকম কিছু হবে:
WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104:
firstResult/maxResults specified with collection fetch; applying in memory!
GO TO FULL VERSION