রুম ডিএও ব্যবহার করে ডেটা অ্যাক্সেস করুন

যখন আপনি আপনার অ্যাপের ডেটা সংরক্ষণের জন্য Room পার্সিস্টেন্স লাইব্রেরি ব্যবহার করেন, তখন আপনি ডেটা অ্যাক্সেস অবজেক্ট বা DAO সংজ্ঞায়িত করার মাধ্যমে সংরক্ষিত ডেটার সাথে ইন্টারঅ্যাক্ট করেন। প্রতিটি DAO-তে এমন ফাংশন থাকে যা আপনার অ্যাপের ডেটাবেসে অ্যাবস্ট্রাক্ট অ্যাক্সেস প্রদান করে। কম্পাইল করার সময়, Room স্বয়ংক্রিয়ভাবে আপনার সংজ্ঞায়িত করা DAO-গুলোর ইমপ্লিমেন্টেশন তৈরি করে।

কোয়েরি বিল্ডার বা সরাসরি কোয়েরির পরিবর্তে আপনার অ্যাপের ডেটাবেস অ্যাক্সেস করার জন্য ডিএও (DAO) ব্যবহার করে, আপনি কনসার্ন সেপারেশন (separation of concerns) বজায় রাখতে পারেন, যা একটি অত্যন্ত গুরুত্বপূর্ণ আর্কিটেকচারাল নীতি। এছাড়াও, আপনার অ্যাপ পরীক্ষা করার সময় ডিএও আপনাকে ডেটাবেস অ্যাক্সেস মক (mock) করার সুযোগ দেয়।

একটি DAO-এর গঠন

আপনি প্রতিটি DAO-কে একটি ইন্টারফেস অথবা একটি অ্যাবস্ট্রাক্ট ক্লাস হিসেবে সংজ্ঞায়িত করতে পারেন। সাধারণ ব্যবহারের ক্ষেত্রে, সাধারণত একটি ইন্টারফেস ব্যবহার করা হয়। উভয় ক্ষেত্রেই, আপনাকে অবশ্যই আপনার DAO-গুলোকে @Dao দিয়ে অ্যানোটেট করতে হবে। DAO-গুলোর কোনো প্রোপার্টি নেই, কিন্তু এগুলো আপনার অ্যাপের ডেটাবেসের ডেটার সাথে ইন্টারঅ্যাক্ট করার জন্য এক বা একাধিক ফাংশন সংজ্ঞায়িত করে।

নিম্নলিখিত কোডটি একটি DAO-এর উদাহরণ, যা একটি Room ডেটাবেসে User অবজেক্ট সন্নিবেশ, মুছে ফেলা এবং নির্বাচন করার জন্য ফাংশন সংজ্ঞায়িত করে:

@Dao
interface UserDao {
    @Insert
    suspend fun insertAll(vararg users: User)

    @Delete
    suspend fun delete(user: User)

    @Query("SELECT * FROM user")
    suspend fun getAll(): List<User>
}

দুই ধরনের DAO ফাংশন রয়েছে যা ডাটাবেস ইন্টারঅ্যাকশন নির্ধারণ করে:

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

নিম্নলিখিত বিভাগগুলিতে দেখানো হয়েছে কীভাবে আপনার অ্যাপের প্রয়োজনীয় ডাটাবেস ইন্টারঅ্যাকশনগুলি সংজ্ঞায়িত করতে উভয় ধরণের DAO ফাংশন ব্যবহার করতে হয়।

সুবিধাজনক কার্যাবলী

Room এমন ফাংশন সংজ্ঞায়িত করার জন্য সুবিধাজনক অ্যানোটেশন প্রদান করে, যা কোনো SQL স্টেটমেন্ট লেখার প্রয়োজন ছাড়াই ডেটা সন্নিবেশ, আপডেট এবং মুছে ফেলার কাজ করে।

যদি আপনাকে আরও জটিল ইনসারশন, আপডেট বা ডিলিশন নির্ধারণ করতে হয়, অথবা ডাটাবেস থেকে ডেটা কোয়েরি করার প্রয়োজন হয়, তাহলে এর পরিবর্তে একটি কোয়েরি ফাংশন ব্যবহার করুন।

ঢোকান

@Insert অ্যানোটেশনটি আপনাকে এমন ফাংশন সংজ্ঞায়িত করতে দেয় যা তাদের প্যারামিটারগুলোকে ডাটাবেসের উপযুক্ত টেবিলে সন্নিবেশ করে। নিম্নলিখিত কোডটি বৈধ @Insert ফাংশনের উদাহরণ দেখায় যা ডাটাবেসে এক বা একাধিক User অবজেক্ট সন্নিবেশ করে:

@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUsers(vararg users: User)

    @Insert
    suspend fun insertBothUsers(user1: User, user2: User)

    @Insert
    suspend fun insertUsersAndFriends(user: User, friends: List<User>)
}

একটি @Insert ফাংশনের প্রতিটি প্যারামিটার অবশ্যই @Entity দ্বারা টীকাযুক্ত একটি Room ডেটা এনটিটি ক্লাসের ইনস্ট্যান্স অথবা ডেটা এনটিটি ক্লাস ইনস্ট্যান্সের একটি সংগ্রহ হতে হবে। যখন একটি @Insert ফাংশন কল করা হয়, Room প্রতিটি প্রদত্ত এনটিটি ইনস্ট্যান্সকে সংশ্লিষ্ট ডাটাবেস টেবিলে সন্নিবেশ করে।

যদি @Insert ফাংশনটি একটিমাত্র প্যারামিটার গ্রহণ করে, তবে এটি একটি Long ভ্যালু রিটার্ন করতে পারে, যা হলো ইনসার্ট করা আইটেমটির নতুন rowId । যদি প্যারামিটারটি একটি অ্যারে বা কালেকশন হয়, তবে এর পরিবর্তে এটি Long ভ্যালুর একটি অ্যারে বা কালেকশন রিটার্ন করবে, যেখানে প্রতিটি ভ্যালু হবে ইনসার্ট করা আইটেমগুলোর মধ্যে একটির rowIdrowId ভ্যালু রিটার্ন করার বিষয়ে আরও জানতে, @Insert অ্যানোটেশনের রেফারেন্স ডকুমেন্টেশন এবং rowid টেবিলের জন্য SQLite ডকুমেন্টেশন দেখুন।

আপডেট

@Update অ্যানোটেশনটি আপনাকে ডাটাবেস টেবিলের নির্দিষ্ট সারি আপডেট করার জন্য ফাংশন সংজ্ঞায়িত করতে দেয়। @Insert ফাংশনের মতোই, @Update ফাংশনগুলো প্যারামিটার হিসেবে ডেটা এনটিটি ইনস্ট্যান্স গ্রহণ করে। নিচের কোডটি একটি @Update ফাংশনের উদাহরণ দেখাচ্ছে যা ডাটাবেসে এক বা একাধিক User অবজেক্ট আপডেট করার চেষ্টা করে:

@Dao
interface UserDao {
    @Update
    suspend fun updateUsers(vararg users: User)
}

Room আর্গুমেন্টে থাকা এনটিটি ইনস্ট্যান্সগুলোকে ডাটাবেসের সারির সাথে মেলানোর জন্য প্রাইমারি কী ব্যবহার করে। যদি একই প্রাইমারি কী সহ কোনো সারি না থাকে, তবে Room কোনো পরিবর্তন করে না।

একটি @Update ফাংশন ঐচ্ছিকভাবে একটি Int ভ্যালু রিটার্ন করতে পারে, যা সফলভাবে আপডেট হওয়া রো-এর সংখ্যা নির্দেশ করে।

মুছে ফেলুন

@Delete অ্যানোটেশনটি আপনাকে ডাটাবেস টেবিল থেকে নির্দিষ্ট সারি মুছে ফেলার জন্য ফাংশন সংজ্ঞায়িত করতে দেয়। @Insert ফাংশনের মতোই, @Delete ফাংশনগুলো প্যারামিটার হিসেবে ডেটা এনটিটি ইনস্ট্যান্স গ্রহণ করে। নিচের কোডটি একটি @Delete ফাংশনের উদাহরণ দেখাচ্ছে যা ডাটাবেস থেকে এক বা একাধিক User অবজেক্ট মুছে ফেলার চেষ্টা করে:

@Dao
interface UserDao {
    @Delete
    suspend fun deleteUsers(vararg users: User)
}

Room আর্গুমেন্টে থাকা এনটিটি ইনস্ট্যান্সগুলোকে ডাটাবেসের সারির সাথে মেলানোর জন্য প্রাইমারি কী ব্যবহার করে। যদি একই প্রাইমারি কী সহ কোনো সারি না থাকে, তবে Room কোনো পরিবর্তন করে না।

একটি @Delete ফাংশন ঐচ্ছিকভাবে একটি Int ভ্যালু রিটার্ন করতে পারে, যা সফলভাবে ডিলিট হওয়া রো-এর সংখ্যা নির্দেশ করে।

উৎস্বাগত

@Upsert অ্যানোটেশনটি আপনাকে এমন ফাংশন সংজ্ঞায়িত করতে দেয় যা কোনো মিলযুক্ত সারি না থাকলে এনটিটি ইনস্ট্যান্স সন্নিবেশ করে, অথবা একই প্রাইমারি কী সহ একটি সারি আগে থেকেই বিদ্যমান থাকলে সেগুলোকে আপডেট করে।

@Insert এবং @Update ফাংশনগুলোর মতোই, @Upsert ফাংশনগুলোও প্যারামিটার হিসেবে ডেটা এনটিটি ইনস্ট্যান্স গ্রহণ করে। নিচের কোডটিতে একটি @Upsert ফাংশনের উদাহরণ দেখানো হয়েছে, যা ডাটাবেসে এক বা একাধিক User অবজেক্ট আপসার্ট করার চেষ্টা করে:

@Dao
interface UserDao {
    @Upsert
    suspend fun upsertUsers(vararg users: User)
}

@Upsert ফাংশনটি যদি একটিমাত্র প্যারামিটার গ্রহণ করে, তবে এটি একটি Long ভ্যালু রিটার্ন করতে পারে। যদি এর ফলে একটি নতুন সারি যুক্ত হয়, তবে এটি নতুন যুক্ত হওয়া সারিটির rowId রিটার্ন করে। যদি এর ফলে কোনো বিদ্যমান সারি আপডেট হয়, তবে এটি -1 রিটার্ন করে। যদি প্যারামিটারটি একটি অ্যারে বা কালেকশন হয়, তবে এর পরিবর্তে Long ভ্যালুর একটি অ্যারে বা কালেকশন রিটার্ন করা উচিত।

কোয়েরি ফাংশন

@Query অ্যানোটেশনটি আপনাকে SQL স্টেটমেন্ট লিখতে এবং সেগুলোকে DAO ফাংশন হিসেবে প্রকাশ করতে দেয়। আপনার অ্যাপের ডেটাবেস থেকে ডেটা কোয়েরি করতে অথবা যখন আরও জটিল ইনসারশন, আপডেট এবং ডিলিশনের প্রয়োজন হয়, তখন এই কোয়েরি ফাংশনগুলো ব্যবহার করুন।

Room কম্পাইল করার সময়েই SQL কোয়েরি যাচাই করে। এর মানে হলো, আপনার কোয়েরিতে কোনো সমস্যা থাকলে, রানটাইম ব্যর্থতার পরিবর্তে একটি কম্পাইলেশন ত্রুটি ঘটে।

সহজ প্রশ্ন

নিম্নলিখিত কোডটি এমন একটি ফাংশন সংজ্ঞায়িত করে যা একটি SELECT কোয়েরি ব্যবহার করে ডাটাবেসের সমস্ত User অবজেক্ট ফেরত দেয়:

@Query("SELECT * FROM user")
suspend fun loadAllUsers(): List<User>

নিম্নলিখিত বিভাগগুলিতে দেখানো হয়েছে কীভাবে সাধারণ ব্যবহারের ক্ষেত্রে এই উদাহরণটি পরিবর্তন করা যায়।

টেবিলের কলামগুলোর একটি উপসেট ফেরত দিন

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

Room আপনাকে আপনার যেকোনো কোয়েরি থেকে একটি ডেটা অবজেক্ট ফেরত দিতে দেয়, যদি আপনি ফলাফলের কলামগুলোকে ফেরত আসা অবজেক্টটির সাথে ম্যাপ করতে পারেন। উদাহরণস্বরূপ, আপনি একজন ব্যবহারকারীর প্রথম এবং শেষ নাম ধারণ করার জন্য নিম্নলিখিত অবজেক্টটি সংজ্ঞায়িত করতে পারেন:

data class NameTuple(
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String
)

তারপর, আপনি আপনার কোয়েরি ফাংশন থেকে সেই ডেটা অবজেক্টটি রিটার্ন করতে পারেন:

@Query("SELECT first_name, last_name FROM user")
suspend fun loadFullName(): List<NameTuple>

যেহেতু কোয়েরিটি first_name এবং last_name কলামের জন্য ভ্যালু রিটার্ন করে, তাই Room এই ভ্যালুগুলোকে NameTuple ক্লাসের প্রপার্টিগুলোর সাথে ম্যাপ করে। যদি কোয়েরিটি এমন কোনো কলাম রিটার্ন করে যা ফেরত আসা অবজেক্টের কোনো প্রপার্টির সাথে ম্যাপ হয় না, তাহলে Room একটি সতর্কবার্তা প্রদর্শন করে।

যদিও পূর্ববর্তী উদাহরণে কলামের একটি উপসেট পুনরুদ্ধার করতে একটি কাস্টম ডেটা ক্লাস ব্যবহার করা হয়েছে, Room সুবিধার জন্য kotlin.Pair এবং kotlin.Triple রিটার্ন করাও সমর্থন করে, যখন কোনো কোয়েরি ঠিক দুই বা তিনটি কলাম রিটার্ন করে। এই টাইপগুলো ব্যবহার করার সময়, কলামগুলো কোয়েরি স্টেটমেন্টে সংজ্ঞায়িত হওয়ার ক্রম অনুসারে ম্যাপ করা হয়, তাই SELECT স্টেটমেন্টে কলামের ক্রম অবশ্যই Pair বা Triple এর টাইপগুলোর ক্রমের সাথে মিলতে হবে।

একটি কোয়েরিতে সহজ প্যারামিটার পাস করুন

বেশিরভাগ সময়, আপনার DAO ফাংশনগুলোকে ফিল্টারিং অপারেশন সম্পাদনের জন্য প্যারামিটার গ্রহণ করতে হয়। Room আপনার কোয়েরিতে ফাংশন প্যারামিটারকে বাইন্ড প্যারামিটার হিসেবে ব্যবহার করা সমর্থন করে।

উদাহরণস্বরূপ, নিম্নলিখিত কোডটি এমন একটি ফাংশন সংজ্ঞায়িত করে যা একটি নির্দিষ্ট বয়সের উপরের সমস্ত ব্যবহারকারীকে ফেরত দেয়:

@Query("SELECT * FROM user WHERE age > :minAge")
suspend fun loadAllUsersOlderThan(minAge: Int): Array<User>

আপনি একটি কোয়েরিতে একাধিক প্যারামিটার পাস করতে পারেন অথবা একই প্যারামিটারকে একাধিকবার উল্লেখ করতে পারেন, যেমনটি নিম্নলিখিত কোডে দেখানো হয়েছে:

@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
suspend fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>

@Query(
    """
    SELECT * FROM user
    WHERE first_name LIKE :search OR last_name LIKE :search
    """
)
suspend fun findUserWithName(search: String): List<User>

একটি কোয়েরিতে একাধিক প্যারামিটার প্রেরণ করুন।

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

উদাহরণস্বরূপ, নিম্নলিখিত কোডটি এমন একটি ফাংশন সংজ্ঞায়িত করে যা অঞ্চলগুলির একটি উপসেট থেকে সমস্ত ব্যবহারকারীর তথ্য ফেরত দেয়:

@Query("SELECT * FROM user WHERE region IN (:regions)")
suspend fun loadUsersFromRegions(regions: List<String>): List<User>

একাধিক টেবিল অনুসন্ধান করুন

আপনার কিছু কোয়েরির ফলাফল গণনা করার জন্য একাধিক টেবিলে অ্যাক্সেসের প্রয়োজন হতে পারে। আপনি আপনার 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
    """
)
suspend fun findBooksBorrowedByName(userName: String): List<Book>

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

interface UserBookDao {
    @Query(
        """
        SELECT user.name AS userName, book.name AS bookName
        FROM user, book
        WHERE user.id = book.user_id
        """
    )
    fun loadUserAndBookNames(): Flow<List<UserBook>>
}

data class UserBook(val userName: String, val bookName: String)

একটি মাল্টিম্যাপ ফেরত দিন

জয়েনিং অপারেশনের জন্য, আপনি অতিরিক্ত ডেটা ক্লাস সংজ্ঞায়িত না করেই মাল্টিম্যাপ রিটার্ন করে এমন কোয়েরি ফাংশন লিখে একাধিক টেবিলের কলাম কোয়েরি করতে পারেন।

একাধিক টেবিল কোয়েরি (Query multiple tables) থেকে উদাহরণটি বিবেচনা করুন। User এবং Book ইনস্ট্যান্সের জোড়া ধারণকারী একটি কাস্টম ডেটা ক্লাসের ইনস্ট্যান্সের তালিকা রিটার্ন করার পরিবর্তে, আপনি সরাসরি আপনার কোয়েরি ফাংশন থেকে User এবং Book এর একটি ম্যাপিং রিটার্ন করতে পারেন:

@Query(
    """
    SELECT * FROM user
    JOIN book ON user.id = book.user_id
    """
)
suspend fun loadUserAndBookNames(): Map<User, List<Book>>

যখন আপনার কোয়েরি ফাংশন একটি মাল্টিম্যাপ রিটার্ন করে, তখন আপনি GROUP BY ক্লজ ব্যবহার করে কোয়েরি লিখতে পারেন, যা আপনাকে উন্নত গণনা এবং ফিল্টারিংয়ের জন্য SQL-এর সক্ষমতা কাজে লাগানোর সুযোগ দেয়। উদাহরণস্বরূপ, আপনি আপনার loadUserAndBookNames ফাংশনটি পরিবর্তন করে শুধুমাত্র সেইসব ইউজারদের রিটার্ন করতে পারেন যাদের তিনটি বা তার বেশি বই চেক আউট করা আছে:

@Query(
    """
    SELECT * FROM user
    JOIN book ON user.id = book.user_id
    GROUP BY user.name HAVING COUNT(book.id) >= 3
    """
)
suspend fun loadUserAndBookNamesGrouped(): Map<User, List<Book>>

যদি আপনার সম্পূর্ণ অবজেক্ট ম্যাপ করার প্রয়োজন না হয়, তাহলে রিটার্ন টাইপের জেনেরিক প্যারামিটারগুলোতে @MapColumn অ্যানোটেশন ব্যবহার করে আপনার কোয়েরিতে নির্দিষ্ট কলামগুলোর মধ্যে ম্যাপিংও রিটার্ন করতে পারেন।

@Query(
    """
    SELECT user.name AS username, book.name AS bookname FROM user
    JOIN book ON user.id = book.user_id
    """
)
suspend fun loadUserAndBookNamesColumns(): Map<
    @MapColumn(columnName = "username") String,
    List<@MapColumn(columnName = "bookname") String>
    >

বিশেষ রিটার্ন প্রকার

অন্যান্য এপিআই লাইব্রেরির সাথে ইন্টিগ্রেশনের জন্য Room কিছু বিশেষ রিটার্ন টাইপ প্রদান করে।

পেজিং লাইব্রেরি ব্যবহার করে পেজিনেটেড কোয়েরি

Room, Paging লাইব্রেরির সাথে ইন্টিগ্রেশনের মাধ্যমে পেজিনেটেড কোয়েরি সমর্থন করে। Paging 3 রিটার্ন টাইপ ব্যবহার করতে হলে, আপনাকে আপনার ডাটাবেস বা DAO-তে Paging রিটার্ন টাইপ কনভার্টারগুলো রেজিস্টার করতে হবে:

  1. আপনার বিল্ড কনফিগারেশনে androidx.room3:room3-paging আর্টিফ্যাক্টটি অন্তর্ভুক্ত করুন।
  2. আপনার @Database অথবা @Dao ডিক্লারেশনকে @DaoReturnTypeConverters(PagingSourceDaoReturnTypeConverter::class) দিয়ে টীকাযুক্ত করুন।

একবার নিবন্ধিত হয়ে গেলে, আপনার DAO-গুলি Paging 3-এর সাথে ব্যবহারের জন্য PagingSource অবজেক্ট ফেরত দিতে পারে:

@Dao
@DaoReturnTypeConverters(PagingSourceDaoReturnTypeConverter::class)
interface UserDao {
    @Query("SELECT * FROM users WHERE label LIKE :query")
    fun pagingSource(query: String): PagingSource<Int, User>
}

একটি PagingSource জন্য টাইপ প্যারামিটার নির্বাচন করার বিষয়ে আরও তথ্যের জন্য, "কী এবং ভ্যালু টাইপ নির্বাচন করুন" দেখুন।

সরাসরি ডাটাবেস সংযোগ অ্যাক্সেস

যদি আপনার অ্যাপের লজিকের জন্য ডাটাবেস কানেকশনে সরাসরি, নিম্ন-স্তরের অ্যাক্সেসের প্রয়োজন হয়, তাহলে আপনি এর পরিবর্তে Room-এর কানেকশন API ব্যবহার করতে পারেন। আপনি আপনার RoomDatabase ইনস্ট্যান্সে শুধুমাত্র-পঠন (read-only) অপারেশনের জন্য useReaderConnection অথবা লেখার (write) অপারেশনের জন্য useWriterConnection ব্যবহার করে একটি কানেকশন পেতে পারেন, এবং স্টেটমেন্ট কার্যকর করার জন্য usePrepared ব্যবহার করতে পারেন:

val result: List<Pair<Long, String>> =
    roomDatabase.useReaderConnection { connection ->
        connection.usePrepared(
            "SELECT * FROM user WHERE age > :minAge LIMIT 5"
        ) { stmt ->
            // Bind arguments if needed
            stmt.bindLong(1, minAge.toLong())
            buildList {
                // Step through the results
                while (stmt.step()) {
                    add(stmt.getLong(0) to stmt.getText(1))
                }
            }
        }
    }

যদি আপনাকে সরাসরি কানেকশনের উপর নিম্ন-স্তরের ডাটাবেস ট্রানজ্যাকশন সম্পাদন করতে হয়, তাহলে আপনি useWriterConnection ব্লকের ভিতরে একটি Transactor ইনস্ট্যান্সে immediateTransaction , deferredTransaction , বা exclusiveTransaction হেল্পার ফাংশনগুলো ব্যবহার করতে পারেন:

roomDatabase.useWriterConnection { transactor ->
    transactor.immediateTransaction {
        // Perform transactional database operations using transactor
    }
}

বিকল্পভাবে, যদি আপনার কোনো ট্রানজ্যাকশনে শুধুমাত্র উচ্চ-স্তরের DAO অপারেশন সম্পাদন করার প্রয়োজন হয়, তাহলে আপনার RoomDatabase ইনস্ট্যান্সে withReadTransaction বা withWriteTransaction হেল্পার এক্সটেনশন ফাংশনগুলো ব্যবহার করুন:

// Perform transactional read operations (DEFERRED transaction)
val userCount = roomDatabase.withReadTransaction {
    userDao.countUsers()
}

// Perform transactional write operations (IMMEDIATE transaction)
roomDatabase.withWriteTransaction {
    userDao.insert(newUser)
    userDao.update(existingUser)
}