রুম ব্যবহার করে জটিল তথ্য উল্লেখ করা

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

টাইপ কনভার্টার ব্যবহার করুন

কখনও কখনও, একটি একক ডাটাবেস কলামে একটি কাস্টম ডেটা টাইপ সংরক্ষণ করার জন্য আপনার অ্যাপের প্রয়োজন হয়৷ আপনি টাইপ রূপান্তরকারী প্রদান করে কাস্টম প্রকারগুলিকে সমর্থন করেন, যেগুলি এমন পদ্ধতি যা রুমকে বলে যে কীভাবে কাস্টম প্রকারগুলিকে পরিচিত টাইপগুলিতে রূপান্তর করতে হয় এবং রুম টিকে থাকতে পারে। আপনি @TypeConverter টীকা ব্যবহার করে টাইপ কনভার্টার শনাক্ত করেন।

ধরুন আপনাকে আপনার রুম ডাটাবেসে Date দৃষ্টান্তগুলি বজায় রাখতে হবে। রুম জানে না কিভাবে Date অবজেক্টগুলি বজায় রাখা যায়, তাই আপনাকে টাইপ রূপান্তরকারী সংজ্ঞায়িত করতে হবে:

কোটলিন

class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? {
    return value?.let { Date(it) }
  }

  @TypeConverter
  fun dateToTimestamp(date: Date?): Long? {
    return date?.time?.toLong()
  }
}

জাভা

public class Converters {
  @TypeConverter
  public static Date fromTimestamp(Long value) {
    return value == null ? null : new Date(value);
  }

  @TypeConverter
  public static Long dateToTimestamp(Date date) {
    return date == null ? null : date.getTime();
  }
}

এই উদাহরণটি দুটি ধরণের রূপান্তরকারী পদ্ধতি সংজ্ঞায়িত করে: একটি যা একটি Date অবজেক্টকে একটি Long বস্তুতে রূপান্তর করে এবং একটি যা Long থেকে Date বিপরীত রূপান্তর সম্পাদন করে। যেহেতু রুম জানে কিভাবে Long অবজেক্টগুলিকে স্থির রাখতে হয়, এটি এই রূপান্তরকারীগুলি ব্যবহার করে Date অবজেক্টগুলিকে বজায় রাখতে পারে।

এর পরে, আপনি AppDatabase ক্লাসে @TypeConverters টীকা যোগ করুন যাতে রুম আপনার সংজ্ঞায়িত কনভার্টার ক্লাস সম্পর্কে জানতে পারে:

কোটলিন

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
  abstract fun userDao(): UserDao
}

জাভা

@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
  public abstract UserDao userDao();
}

এই ধরনের রূপান্তরকারী সংজ্ঞায়িত করে, আপনি আপনার সত্তা এবং DAO-তে আপনার কাস্টম টাইপ ব্যবহার করতে পারেন ঠিক যেমন আপনি আদিম প্রকারগুলি ব্যবহার করবেন:

কোটলিন

@Entity
data class User(private val birthday: Date?)

@Dao
interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  fun findUsersBornOnDate(targetDate: Date): List<User>
}

জাভা

@Entity
public class User {
  private Date birthday;
}

@Dao
public interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  List<User> findUsersBornOnDate(Date targetDate);
}

এই উদাহরণে, রুম সর্বত্র সংজ্ঞায়িত টাইপ কনভার্টার ব্যবহার করতে পারে কারণ আপনি @TypeConverters এর সাথে AppDatabase টীকা করেছেন। যাইহোক, আপনি @TypeConverters এর সাথে আপনার @Entity বা @Dao ক্লাসে টীকা দিয়ে নির্দিষ্ট সত্তা বা DAO-তে স্কোপ টাইপ কনভার্টারগুলিও করতে পারেন।

কন্ট্রোল টাইপ কনভার্টার ইনিশিয়ালাইজেশন

সাধারণত, রুম আপনার জন্য টাইপ কনভার্টারগুলির ইনস্ট্যান্টেশন পরিচালনা করে। যাইহোক, কখনও কখনও আপনাকে আপনার টাইপ কনভার্টার ক্লাসে অতিরিক্ত নির্ভরতা পাস করতে হতে পারে, যার অর্থ হল আপনার টাইপ কনভার্টারগুলির প্রারম্ভিকতা নিয়ন্ত্রণ করতে আপনার অ্যাপের প্রয়োজন। সেই ক্ষেত্রে, @ProvidedTypeConverter এর সাথে আপনার কনভার্টার ক্লাস টীকা করুন:

কোটলিন

@ProvidedTypeConverter
class ExampleConverter {
  @TypeConverter
  fun StringToExample(string: String?): ExampleType? {
    ...
  }

  @TypeConverter
  fun ExampleToString(example: ExampleType?): String? {
    ...
  }
}

জাভা

@ProvidedTypeConverter
public class ExampleConverter {
  @TypeConverter
  public Example StringToExample(String string) {
    ...
  }

  @TypeConverter
  public String ExampleToString(Example example) {
    ...
  }
}

তারপর, @TypeConverters এ আপনার কনভার্টার ক্লাস ঘোষণা করার পাশাপাশি, RoomDatabase.Builder.addTypeConverter() পদ্ধতি ব্যবহার করুন আপনার কনভার্টার ক্লাসের একটি উদাহরণ RoomDatabase বিল্ডারকে দিতে:

কোটলিন

val db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build()

জাভা

AppDatabase db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build();

বুঝুন কেন রুম অবজেক্ট রেফারেন্সের অনুমতি দেয় না

মূল টেকঅ্যাওয়ে: রুমটি সত্তা ক্লাসের মধ্যে অবজেক্ট রেফারেন্সকে অনুমোদন করে না। পরিবর্তে, আপনার অ্যাপের প্রয়োজনীয় ডেটার জন্য আপনাকে স্পষ্টভাবে অনুরোধ করতে হবে।

একটি ডাটাবেস থেকে সংশ্লিষ্ট অবজেক্ট মডেলে সম্পর্ক ম্যাপ করা একটি সাধারণ অভ্যাস এবং সার্ভারের দিকে খুব ভাল কাজ করে। এমনকি যখন প্রোগ্রামটি ক্ষেত্রগুলিকে অ্যাক্সেস করার সাথে সাথে লোড করে, তখনও সার্ভারটি ভাল কাজ করে।

যাইহোক, ক্লায়েন্টের পক্ষে, এই ধরণের অলস লোডিং সম্ভব নয় কারণ এটি সাধারণত UI থ্রেডে ঘটে এবং UI থ্রেডে ডিস্কের তথ্য অনুসন্ধান করা উল্লেখযোগ্য কর্মক্ষমতা সমস্যা তৈরি করে। UI থ্রেডে সাধারণত একটি অ্যাক্টিভিটির আপডেট করা লেআউট গণনা করতে এবং আঁকার জন্য প্রায় 16 ms থাকে, তাই এমনকি যদি একটি ক্যোয়ারী মাত্র 5 ms লাগে, তবুও সম্ভবত আপনার অ্যাপের ফ্রেমটি আঁকতে সময় শেষ হয়ে যাবে, যার ফলে লক্ষণীয় দৃশ্যগত ত্রুটি দেখা দেবে। সমান্তরালভাবে একটি পৃথক লেনদেন চলমান থাকলে বা ডিভাইসটি অন্যান্য ডিস্ক-নিবিড় কাজগুলি চালালে ক্যোয়ারীটি সম্পূর্ণ হতে আরও বেশি সময় নিতে পারে। আপনি যদি অলস লোডিং ব্যবহার না করেন তবে, আপনার অ্যাপটি প্রয়োজনের চেয়ে বেশি ডেটা আনে, মেমরি খরচের সমস্যা তৈরি করে।

অবজেক্ট-রিলেশনাল ম্যাপিংগুলি সাধারণত এই সিদ্ধান্তটি ডেভেলপারদের উপর ছেড়ে দেয় যাতে তারা তাদের অ্যাপের ব্যবহারের ক্ষেত্রে সর্বোত্তম যা কিছু করতে পারে। বিকাশকারীরা সাধারণত তাদের অ্যাপ এবং UI এর মধ্যে মডেল ভাগ করার সিদ্ধান্ত নেয়। যদিও এই সমাধানটি ভালভাবে পরিমাপ করে না, কারণ সময়ের সাথে সাথে UI পরিবর্তিত হওয়ার সাথে সাথে ভাগ করা মডেলটি এমন সমস্যা তৈরি করে যা বিকাশকারীদের পক্ষে অনুমান করা এবং ডিবাগ করা কঠিন।

উদাহরণস্বরূপ, একটি UI বিবেচনা করুন যা Book অবজেক্টের একটি তালিকা লোড করে, প্রতিটি বইয়ের একটি Author অবজেক্ট থাকে। Book লেখককে পুনরুদ্ধার করার উদাহরণ পেতে আপনি অলস লোডিং ব্যবহার করার জন্য প্রাথমিকভাবে আপনার প্রশ্নগুলি ডিজাইন করতে পারেন। author ক্ষেত্রের প্রথম পুনরুদ্ধার ডাটাবেস প্রশ্ন. কিছু সময় পরে, আপনি বুঝতে পারেন যে আপনাকে আপনার অ্যাপের UI-তে লেখকের নামও প্রদর্শন করতে হবে। আপনি এই নামটি যথেষ্ট সহজে অ্যাক্সেস করতে পারেন, যেমনটি নিম্নলিখিত কোড স্নিপেটে দেখানো হয়েছে:

কোটলিন

authorNameTextView.text = book.author.name

জাভা

authorNameTextView.setText(book.getAuthor().getName());

যাইহোক, এই আপাতদৃষ্টিতে নির্দোষ পরিবর্তনের কারণে Author টেবিলকে মূল থ্রেডে জিজ্ঞাসা করা হয়।

আপনি যদি সময়ের আগে লেখকের তথ্য জিজ্ঞাসা করেন, আপনার যদি সেই ডেটার আর প্রয়োজন না থাকে তবে কীভাবে ডেটা লোড হয় তা পরিবর্তন করা কঠিন হয়ে পড়ে। উদাহরণস্বরূপ, যদি আপনার অ্যাপের UI আর Author তথ্য প্রদর্শনের প্রয়োজন না হয়, তাহলে আপনার অ্যাপ কার্যকরভাবে ডেটা লোড করে যা এটি আর প্রদর্শন করে না, মূল্যবান মেমরির স্থান নষ্ট করে। আপনার অ্যাপের কার্যকারিতা আরও কমে যায় যদি Author শ্রেণী অন্য টেবিলের উল্লেখ করে, যেমন Books

রুম ব্যবহার করে একই সময়ে একাধিক সত্তার উল্লেখ করতে, আপনি পরিবর্তে একটি POJO তৈরি করুন যাতে প্রতিটি সত্তা রয়েছে, তারপর একটি প্রশ্ন লিখুন যা সংশ্লিষ্ট টেবিলে যোগ দেয়। এই সুগঠিত মডেল, রুমের দৃঢ় ক্যোয়ারী বৈধতা ক্ষমতার সাথে মিলিত, আপনার অ্যাপটিকে ডেটা লোড করার সময়, আপনার অ্যাপের কর্মক্ষমতা এবং ব্যবহারকারীর অভিজ্ঞতা উন্নত করার সময় কম সংস্থান খরচ করতে দেয়।