আপনি যখন আপনার অ্যাপের ডেটা সঞ্চয় করার জন্য রুম পারসিসটেন্স লাইব্রেরি ব্যবহার করেন, তখন আপনি ডেটা অ্যাক্সেস অবজেক্ট বা DAOs সংজ্ঞায়িত করে সঞ্চিত ডেটার সাথে ইন্টারঅ্যাক্ট করেন। প্রতিটি DAO-তে এমন পদ্ধতি রয়েছে যা আপনার অ্যাপের ডাটাবেসে বিমূর্ত অ্যাক্সেস অফার করে। কম্পাইলের সময়, রুম স্বয়ংক্রিয়ভাবে আপনার সংজ্ঞায়িত DAO-এর বাস্তবায়ন তৈরি করে।
ক্যোয়ারী নির্মাতা বা সরাসরি প্রশ্নের পরিবর্তে আপনার অ্যাপের ডাটাবেস অ্যাক্সেস করতে DAOs ব্যবহার করে, আপনি উদ্বেগের বিচ্ছেদ সংরক্ষণ করতে পারেন, একটি গুরুত্বপূর্ণ স্থাপত্য নীতি। আপনি যখন আপনার অ্যাপ পরীক্ষা করেন তখন DAOs আপনার জন্য ডাটাবেস অ্যাক্সেসকে উপহাস করা সহজ করে তোলে।
একটি DAO এর শারীরস্থান
আপনি প্রতিটি DAO কে একটি ইন্টারফেস বা একটি বিমূর্ত শ্রেণী হিসাবে সংজ্ঞায়িত করতে পারেন। মৌলিক ব্যবহারের ক্ষেত্রে, আপনি সাধারণত একটি ইন্টারফেস ব্যবহার করেন। উভয় ক্ষেত্রেই, আপনাকে সর্বদা @Dao
এর সাথে আপনার DAOs টীকা করতে হবে। DAO-এর কোনো বৈশিষ্ট্য নেই, কিন্তু তারা আপনার অ্যাপের ডাটাবেসের ডেটার সাথে ইন্টারঅ্যাক্ট করার জন্য এক বা একাধিক পদ্ধতি সংজ্ঞায়িত করে।
নিম্নলিখিত কোডটি একটি সাধারণ DAO-এর একটি উদাহরণ যা একটি রুম ডাটাবেসে User
বস্তু সন্নিবেশ করা, মুছে ফেলা এবং নির্বাচন করার পদ্ধতিগুলিকে সংজ্ঞায়িত করে:
কোটলিন
@Dao interface UserDao { @Insert fun insertAll(vararg users: User) @Delete fun delete(user: User) @Query("SELECT * FROM user") fun getAll(): List<User> }
জাভা
@Dao public interface UserDao { @Insert void insertAll(User... users); @Delete void delete(User user); @Query("SELECT * FROM user") List<User> getAll(); }
ডাটাবেস মিথস্ক্রিয়া সংজ্ঞায়িত করে এমন দুটি ধরণের DAO পদ্ধতি রয়েছে:
- সুবিধার পদ্ধতি যা আপনাকে কোনো SQL কোড না লিখেই আপনার ডাটাবেসে সারি ঢোকাতে, আপডেট করতে এবং মুছে দিতে দেয়।
- ক্যোয়ারী পদ্ধতি যা আপনাকে ডাটাবেসের সাথে ইন্টারঅ্যাক্ট করতে আপনার নিজস্ব SQL ক্যোয়ারী লিখতে দেয়।
নিম্নলিখিত বিভাগগুলি প্রদর্শন করে যে কীভাবে আপনার অ্যাপের প্রয়োজনীয় ডাটাবেস ইন্টারঅ্যাকশনগুলিকে সংজ্ঞায়িত করতে উভয় ধরনের DAO পদ্ধতি ব্যবহার করতে হয়।
সুবিধার পদ্ধতি
রুম আপনাকে একটি SQL বিবৃতি লেখার প্রয়োজন ছাড়াই সহজ সন্নিবেশ, আপডেট এবং মুছে ফেলার পদ্ধতিগুলি সংজ্ঞায়িত করার জন্য সুবিধাজনক টীকা প্রদান করে।
আপনি যদি আরও জটিল সন্নিবেশ, আপডেট, বা মুছে ফেলার সংজ্ঞায়িত করতে চান, বা আপনার যদি ডাটাবেসের ডেটা অনুসন্ধান করার প্রয়োজন হয় তবে পরিবর্তে একটি ক্যোয়ারী পদ্ধতি ব্যবহার করুন।
ঢোকান
@Insert
টীকাটি আপনাকে এমন পদ্ধতিগুলিকে সংজ্ঞায়িত করতে দেয় যা ডাটাবেসের উপযুক্ত টেবিলে তাদের পরামিতি সন্নিবেশ করায়। নিম্নলিখিত কোডটি বৈধ @Insert
পদ্ধতির উদাহরণ দেখায় যা ডাটাবেসে এক বা একাধিক User
বস্তু সন্নিবেশ করায়:
কোটলিন
@Dao interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertUsers(vararg users: User) @Insert fun insertBothUsers(user1: User, user2: User) @Insert fun insertUsersAndFriends(user: User, friends: List<User>) }
জাভা
@Dao public interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) public void insertUsers(User... users); @Insert public void insertBothUsers(User user1, User user2); @Insert public void insertUsersAndFriends(User user, List<User> friends); }
@Insert
পদ্ধতির জন্য প্রতিটি প্যারামিটার অবশ্যই @Entity
এর সাথে টীকা করা রুম ডেটা এন্টিটি ক্লাসের একটি উদাহরণ হতে হবে অথবা ডেটা এন্টিটি ক্লাস ইনস্ট্যান্সের একটি সংগ্রহ, যার প্রতিটি একটি ডাটাবেসের দিকে নির্দেশ করে। যখন একটি @Insert
পদ্ধতি কল করা হয়, রুম সংশ্লিষ্ট ডাটাবেস টেবিলে প্রতিটি পাস করা সত্তার উদাহরণ সন্নিবেশ করে।
যদি @Insert
পদ্ধতিটি একটি একক প্যারামিটার পায়, তাহলে এটি একটি long
মান ফেরত দিতে পারে, যা সন্নিবেশিত আইটেমের জন্য নতুন rowId
। যদি প্যারামিটারটি একটি অ্যারে বা একটি সংগ্রহ হয়, তাহলে সন্নিবেশ করা আইটেমগুলির একটির জন্য প্রতিটি মানকে rowId
হিসাবে এর পরিবর্তে একটি অ্যারে বা long
মানের একটি সংগ্রহ ফেরত দিন। rowId
মান ফেরানোর বিষয়ে আরও জানতে, @Insert
টীকা এবং rowid টেবিলের জন্য SQLite ডকুমেন্টেশনের রেফারেন্স ডকুমেন্টেশন দেখুন।
আপডেট
@Update
টীকাটি আপনাকে এমন পদ্ধতিগুলি সংজ্ঞায়িত করতে দেয় যা একটি ডাটাবেস টেবিলে নির্দিষ্ট সারি আপডেট করে। @Insert
পদ্ধতির মত, @Update
পদ্ধতিগুলি ডেটা সত্তা দৃষ্টান্তগুলিকে প্যারামিটার হিসাবে গ্রহণ করে। নিম্নলিখিত কোডটি একটি @Update
পদ্ধতির একটি উদাহরণ দেখায় যা ডাটাবেসে এক বা একাধিক User
অবজেক্ট আপডেট করার চেষ্টা করে:
কোটলিন
@Dao interface UserDao { @Update fun updateUsers(vararg users: User) }
জাভা
@Dao public interface UserDao { @Update public void updateUsers(User... users); }
রুম প্রাথমিক কী ব্যবহার করে পাস করা সত্তার দৃষ্টান্তগুলিকে ডাটাবেসের সারিগুলির সাথে মেলাতে। একই প্রাথমিক কী সহ কোন সারি না থাকলে, রুম কোন পরিবর্তন করে না।
একটি @Update
পদ্ধতি ঐচ্ছিকভাবে সফলভাবে আপডেট হওয়া সারিগুলির সংখ্যা নির্দেশ করে একটি int
মান ফেরত দিতে পারে।
মুছে দিন
@Delete
টীকাটি আপনাকে এমন পদ্ধতিগুলি সংজ্ঞায়িত করতে দেয় যা একটি ডাটাবেস টেবিল থেকে নির্দিষ্ট সারি মুছে দেয়। @Insert
পদ্ধতির মত, @Delete
পদ্ধতিগুলি ডেটা সত্তা দৃষ্টান্তগুলিকে প্যারামিটার হিসাবে গ্রহণ করে। নিম্নলিখিত কোডটি @Delete
পদ্ধতির একটি উদাহরণ দেখায় যা ডাটাবেস থেকে এক বা একাধিক User
বস্তু মুছে ফেলার চেষ্টা করে:
কোটলিন
@Dao interface UserDao { @Delete fun deleteUsers(vararg users: User) }
জাভা
@Dao public interface UserDao { @Delete public void deleteUsers(User... users); }
রুম প্রাথমিক কী ব্যবহার করে পাস করা সত্তার দৃষ্টান্তগুলিকে ডাটাবেসের সারিগুলির সাথে মেলাতে। একই প্রাথমিক কী সহ কোন সারি না থাকলে, রুম কোন পরিবর্তন করে না।
একটি @Delete
পদ্ধতি ঐচ্ছিকভাবে সফলভাবে মুছে ফেলা সারিগুলির সংখ্যা নির্দেশ করে একটি int
মান প্রদান করতে পারে।
প্রশ্ন পদ্ধতি
@Query
টীকা আপনাকে SQL বিবৃতি লিখতে এবং DAO পদ্ধতি হিসাবে প্রকাশ করতে দেয়। আপনার অ্যাপের ডাটাবেস থেকে ডেটা অনুসন্ধান করতে বা যখন আপনার আরও জটিল সন্নিবেশ, আপডেট এবং মুছে ফেলার প্রয়োজন হয় তখন এই ক্যোয়ারী পদ্ধতিগুলি ব্যবহার করুন৷
রুম কম্পাইল সময়ে SQL প্রশ্ন যাচাই করে। এর মানে হল যে আপনার ক্যোয়ারীতে কোনো সমস্যা হলে, রানটাইম ব্যর্থতার পরিবর্তে একটি সংকলন ত্রুটি দেখা দেয়।
সহজ প্রশ্ন
নিম্নলিখিত কোডটি এমন একটি পদ্ধতিকে সংজ্ঞায়িত করে যা ডাটাবেসের সমস্ত User
অবজেক্ট ফেরত দিতে একটি সাধারণ SELECT
ক্যোয়ারী ব্যবহার করে:
কোটলিন
@Query("SELECT * FROM user") fun loadAllUsers(): Array<User>
জাভা
@Query("SELECT * FROM user") public User[] loadAllUsers();
নিম্নলিখিত বিভাগগুলি প্রদর্শন করে যে কীভাবে সাধারণ ব্যবহারের ক্ষেত্রে এই উদাহরণটি সংশোধন করতে হয়।
একটি টেবিলের কলামের একটি উপসেট ফেরত দিন
বেশিরভাগ সময়, আপনি যে টেবিলটি অনুসন্ধান করছেন তা থেকে আপনাকে শুধুমাত্র কলামগুলির একটি উপসেট ফেরত দিতে হবে। উদাহরণস্বরূপ, আপনার UI সেই ব্যবহারকারী সম্পর্কে প্রতিটি বিশদ বিবরণের পরিবর্তে একজন ব্যবহারকারীর জন্য শুধুমাত্র প্রথম এবং শেষ নাম প্রদর্শন করতে পারে। সম্পদ সংরক্ষণ করতে এবং আপনার ক্যোয়ারী এক্সিকিউশনকে স্ট্রীমলাইন করতে, শুধুমাত্র আপনার প্রয়োজনীয় ক্ষেত্রগুলি ক্যোয়ারী করুন।
রুম আপনাকে আপনার যেকোন প্রশ্ন থেকে একটি সাধারণ বস্তু ফেরত দিতে দেয় যতক্ষণ না আপনি ফলাফলের কলামের সেটটিকে ফিরে আসা বস্তুতে ম্যাপ করতে পারেন। উদাহরণস্বরূপ, আপনি ব্যবহারকারীর প্রথম এবং শেষ নাম ধরে রাখতে নিম্নলিখিত অবজেক্টটি সংজ্ঞায়িত করতে পারেন:
কোটলিন
data class NameTuple( @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
জাভা
public class NameTuple { @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") @NonNull public String lastName; }
তারপর, আপনি আপনার ক্যোয়ারী পদ্ধতি থেকে সেই সহজ বস্তুটি ফেরত দিতে পারেন:
কোটলিন
@Query("SELECT first_name, last_name FROM user") fun loadFullName(): List<NameTuple>
জাভা
@Query("SELECT first_name, last_name FROM user") public List<NameTuple> loadFullName();
রুম বুঝতে পারে যে ক্যোয়ারী first_name
এবং last_name
কলামগুলির জন্য মান প্রদান করে এবং এই মানগুলিকে NameTuple
ক্লাসের ক্ষেত্রের মধ্যে ম্যাপ করা যেতে পারে। যদি প্রশ্নটি এমন একটি কলাম প্রদান করে যা প্রত্যাবর্তিত বস্তুর একটি ক্ষেত্রের উপর ম্যাপ করে না, রুম একটি সতর্কতা প্রদর্শন করে।
একটি প্রশ্নে সহজ পরামিতি পাস করুন
বেশিরভাগ সময়, আপনার DAO পদ্ধতিগুলিকে পরামিতিগুলি গ্রহণ করতে হবে যাতে তারা ফিল্টারিং ক্রিয়াকলাপ সম্পাদন করতে পারে। রুম আপনার প্রশ্নের মধ্যে বাঁধাই পরামিতি হিসাবে পদ্ধতি পরামিতি ব্যবহার সমর্থন করে।
উদাহরণস্বরূপ, নিম্নলিখিত কোডটি একটি পদ্ধতি সংজ্ঞায়িত করে যা একটি নির্দিষ্ট বয়সের উপরে সমস্ত ব্যবহারকারীকে ফেরত দেয়:
কোটলিন
@Query("SELECT * FROM user WHERE age > :minAge") fun loadAllUsersOlderThan(minAge: Int): Array<User>
জাভা
@Query("SELECT * FROM user WHERE age > :minAge") public User[] loadAllUsersOlderThan(int minAge);
আপনি একাধিক পরামিতি পাস করতে পারেন বা একটি ক্যোয়ারীতে একই প্যারামিটার একাধিকবার উল্লেখ করতে পারেন, যেমনটি নিম্নলিখিত কোডে প্রদর্শিত হয়েছে:
কোটলিন
@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge") fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User> @Query("SELECT * FROM user WHERE first_name LIKE :search " + "OR last_name LIKE :search") fun findUserWithName(search: String): List<User>
জাভা
@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge") public User[] loadAllUsersBetweenAges(int minAge, int maxAge); @Query("SELECT * FROM user WHERE first_name LIKE :search " + "OR last_name LIKE :search") public List<User> findUserWithName(String search);
একটি প্রশ্নের পরামিতি সংগ্রহ পাস
আপনার কিছু DAO পদ্ধতির জন্য আপনাকে পরিবর্তনশীল সংখ্যক প্যারামিটারে পাস করতে হতে পারে যা রানটাইম পর্যন্ত জানা যায় না। রুম বুঝতে পারে যখন একটি প্যারামিটার একটি সংগ্রহের প্রতিনিধিত্ব করে এবং প্রদত্ত প্যারামিটারের সংখ্যার উপর ভিত্তি করে রানটাইমে এটি স্বয়ংক্রিয়ভাবে প্রসারিত করে।
উদাহরণস্বরূপ, নিম্নলিখিত কোডটি এমন একটি পদ্ধতিকে সংজ্ঞায়িত করে যা অঞ্চলগুলির একটি উপসেট থেকে সমস্ত ব্যবহারকারী সম্পর্কে তথ্য প্রদান করে:
কোটলিন
@Query("SELECT * FROM user WHERE region IN (:regions)") fun loadUsersFromRegions(regions: List<String>): List<User>
জাভা
@Query("SELECT * FROM user WHERE region IN (:regions)") public List<User> loadUsersFromRegions(List<String> regions);
একাধিক টেবিল জিজ্ঞাসা করুন
ফলাফল গণনা করার জন্য আপনার কিছু প্রশ্নের একাধিক টেবিলে অ্যাক্সেসের প্রয়োজন হতে পারে। আপনি একাধিক টেবিল রেফারেন্স করতে আপনার SQL ক্যোয়ারীতে JOIN
ক্লজ ব্যবহার করতে পারেন।
নিম্নলিখিত কোডটি একটি পদ্ধতি সংজ্ঞায়িত করে যা একটি নির্দিষ্ট ব্যবহারকারীকে বর্তমানে ঋণে থাকা বইগুলিকে ফেরত দেওয়ার জন্য তিনটি টেবিলের সাথে যোগ দেয়:
কোটলিন
@Query( "SELECT * FROM book " + "INNER JOIN loan ON loan.book_id = book.id " + "INNER JOIN user ON user.id = loan.user_id " + "WHERE user.name LIKE :userName" ) fun findBooksBorrowedByNameSync(userName: String): List<Book>
জাভা
@Query("SELECT * FROM book " + "INNER JOIN loan ON loan.book_id = book.id " + "INNER JOIN user ON user.id = loan.user_id " + "WHERE user.name LIKE :userName") public List<Book> findBooksBorrowedByNameSync(String userName);
আপনি একাধিক যোগ করা টেবিল থেকে কলামের একটি উপসেট ফেরত দেওয়ার জন্য সাধারণ বস্তুগুলিকেও সংজ্ঞায়িত করতে পারেন, যেমন একটি টেবিলের কলাম বিভাগে একটি উপসেট ফেরত দিন আলোচনা করা হয়েছে। নিম্নলিখিত কোডটি একটি পদ্ধতির সাথে একটি DAO কে সংজ্ঞায়িত করে যা ব্যবহারকারীদের নাম এবং তারা যে বইগুলি ধার করেছে তার নাম ফেরত দেয়:
কোটলিন
interface UserBookDao { @Query( "SELECT user.name AS userName, book.name AS bookName " + "FROM user, book " + "WHERE user.id = book.user_id" ) fun loadUserAndBookNames(): LiveData<List<UserBook>> // You can also define this class in a separate file. data class UserBook(val userName: String?, val bookName: String?) }
জাভা
@Dao public interface UserBookDao { @Query("SELECT user.name AS userName, book.name AS bookName " + "FROM user, book " + "WHERE user.id = book.user_id") public LiveData<List<UserBook>> loadUserAndBookNames(); // You can also define this class in a separate file, as long as you add the // "public" access modifier. static class UserBook { public String userName; public String bookName; } }
একটি মাল্টিম্যাপ ফেরত দিন
রুম 2.4 এবং উচ্চতর, আপনি একটি মাল্টিম্যাপ প্রদানকারী ক্যোয়ারী পদ্ধতিগুলি লিখে অতিরিক্ত ডেটা ক্লাস নির্ধারণ না করে একাধিক টেবিল থেকে কলামগুলি অনুসন্ধান করতে পারেন।
ক্যোয়ারী একাধিক টেবিল বিভাগ থেকে উদাহরণ বিবেচনা করুন. একটি কাস্টম ডেটা ক্লাসের উদাহরণগুলির একটি তালিকা ফেরত দেওয়ার পরিবর্তে যা User
এবং Book
উদাহরণগুলির জোড়া রয়েছে, আপনি আপনার ক্যোয়ারী পদ্ধতি থেকে সরাসরি User
এবং Book
একটি ম্যাপিং ফিরিয়ে দিতে পারেন:
কোটলিন
@Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" ) fun loadUserAndBookNames(): Map<User, List<Book>>
জাভা
@Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" ) public Map<User, List<Book>> loadUserAndBookNames();
যখন আপনার ক্যোয়ারী পদ্ধতিটি একটি মাল্টিম্যাপ প্রদান করে, তখন আপনি এমন প্রশ্ন লিখতে পারেন যা GROUP BY
ধারাগুলি ব্যবহার করে, আপনাকে উন্নত গণনা এবং ফিল্টারিংয়ের জন্য SQL এর ক্ষমতার সুবিধা নিতে দেয়৷ উদাহরণ স্বরূপ, আপনি আপনার loadUserAndBookNames()
পদ্ধতি পরিবর্তন করতে পারেন শুধুমাত্র তিন বা ততোধিক বই চেক আউট করা ব্যবহারকারীদের ফিরিয়ে দিতে:
কোটলিন
@Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" + "GROUP BY user.name WHERE COUNT(book.id) >= 3" ) fun loadUserAndBookNames(): Map<User, List<Book>>
জাভা
@Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" + "GROUP BY user.name WHERE COUNT(book.id) >= 3" ) public Map<User, List<Book>> loadUserAndBookNames();
আপনার যদি সম্পূর্ণ অবজেক্ট ম্যাপ করার প্রয়োজন না হয়, তাহলে আপনি আপনার ক্যোয়ারী পদ্ধতিতে @MapInfo
টীকায় keyColumn
এবং valueColumn
অ্যাট্রিবিউট সেট করে আপনার প্রশ্নের নির্দিষ্ট কলামগুলির মধ্যে ম্যাপিংগুলি ফেরত দিতে পারেন:
কোটলিন
@MapInfo(keyColumn = "userName", valueColumn = "bookName") @Query( "SELECT user.name AS username, book.name AS bookname FROM user" + "JOIN book ON user.id = book.user_id" ) fun loadUserAndBookNames(): Map<String, List<String>>
জাভা
@MapInfo(keyColumn = "userName", valueColumn = "bookName") @Query( "SELECT user.name AS username, book.name AS bookname FROM user" + "JOIN book ON user.id = book.user_id" ) public Map<String, List<String>> loadUserAndBookNames();
বিশেষ রিটার্ন প্রকার
রুম অন্যান্য API লাইব্রেরির সাথে একীকরণের জন্য কিছু বিশেষ ধরনের রিটার্ন প্রদান করে।
পেজিং লাইব্রেরির সাথে পেজিনেটেড প্রশ্ন
রুম পেজিং লাইব্রেরির সাথে একীকরণের মাধ্যমে পৃষ্ঠাযুক্ত প্রশ্ন সমর্থন করে। রুম 2.3.0-alpha01 এবং উচ্চতর, DAOs পেজিং 3 এর সাথে ব্যবহারের জন্য PagingSource
অবজেক্টগুলি ফেরত দিতে পারে।
কোটলিন
@Dao interface UserDao { @Query("SELECT * FROM users WHERE label LIKE :query") fun pagingSource(query: String): PagingSource<Int, User> }
জাভা
@Dao interface UserDao { @Query("SELECT * FROM users WHERE label LIKE :query") PagingSource<Integer, User> pagingSource(String query); }
PagingSource
জন্য টাইপ প্যারামিটার নির্বাচন করার বিষয়ে আরও তথ্যের জন্য, কী এবং মান প্রকার নির্বাচন করুন দেখুন।
সরাসরি কার্সার অ্যাক্সেস
যদি আপনার অ্যাপের যুক্তির জন্য রিটার্ন সারিগুলিতে সরাসরি অ্যাক্সেসের প্রয়োজন হয়, আপনি একটি Cursor
অবজেক্ট ফেরত দেওয়ার জন্য আপনার DAO পদ্ধতিগুলি লিখতে পারেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
@Dao interface UserDao { @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") fun loadRawUsersOlderThan(minAge: Int): Cursor }
জাভা
@Dao public interface UserDao { @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") public Cursor loadRawUsersOlderThan(int minAge); }
অতিরিক্ত সম্পদ
রুম DAO ব্যবহার করে ডেটা অ্যাক্সেস করার বিষয়ে আরও জানতে, নিম্নলিখিত অতিরিক্ত সংস্থানগুলি দেখুন: