Realm، یک کتابخانه پایدار توسط MongoDB، به شما امکان می دهد به راحتی object ها را به صورت محلی ذخیره کنید. در این آموزش، اپلیکیشنی به نام PetRealm ایجاد خواهید کرد که از پایگاه داده Realm برای ذخیره اطلاعات در مورد حیوانات خانگی و صاحبان استفاده می کند.
این برنامه به کاربر امکان می دهد حیوانات خانگی را برای فرزندخواندگی اضافه کند، صاحبان خود را اضافه کند و لیستی از حیوانات خانگی را که به فرزندی پذیرفته شده است را نشان دهد. این امکان را دارد که یک حیوان خانگی را با اختصاص مالک به آن به فرزندی قبول کند.

در طول این آموزش، با موارد زیر آشنا خواهید شد:

  • دیتابیس realm
  • Schema ها وموجودیت ها(entity)
  • درج آبجکت ها
  • پرس و جو(Query) و حذف آبجکت
  • روابط (Relationship) بین موجودیت ها
  • Realm Studio
  • مقایسهRealm و Room

با کلیک بر روی دکمه دانلود در پایین این مقاله ، مطالب را دانلود کنید.

در زیر خلاصه ای از کارهایی که هر بسته انجام می دهد آورده شده است:

  • common : شامل کلاس های مورد استفاده در بخش های مختلف برنامه است.
  • di: کلاس هایی برای ارائه تزریق وابستگی در اینجا پیدا خواهید کرد.
  • owners: شامل کلاس های مربوط به مالکان است.
  • pets: شامل کلاس های مربوط به حیوانات خانگی است.
  • realm: در اینجا، تمام کلاس های مربوط به Realm را پیدا خواهید کرد.

برنامه را build و run کنید. صفحه ای با bottom navigation bar ، یک button برای افزودن حیوانات خانگی(pets) و spinner مشاهده خواهید کرد.

button را فشار دهید ، در نهایت صفحه ای برای افزودن حیوانات خانگی مشاهده خواهید کرد، همانطور که در زیر نشان داده شده است :

صفحه را dismiss کنید و گزینه Adopted pets را در navigation bar فشار دهید. صفحه خالی زیر را خواهید دید:

در نهایت، آیکون Owners را در bottom navigation bar فشار دهید. این صفحه ، owners (دارنده ها) را نشان می دهد. دکمه افزودن را فشار دهید و صفحه زیر را مشاهده خواهید کرد:

برنامه تقریباً خالی است. وقت آن است که در مورد Realm بیاموزید و از آن در این برنامه استفاده کنید.

معرفی Realm

دیتابیس Realm یک سیستم مدیریت دیتابیس object است. این نوع دیتابیس ، موجودیت های خود را تحت عنوان object نشان می دهد.

نکته مهم این است که Realm با ACID سازگار است. این بدان معنی است که :

  • atomicity: در Realm تمام عملیات در یک تراکنش گروه بندی می شود. اگر هر یک از عملیات fail شود، دیتابیس همه عملیات را به عقب برمی گرداند.
  • ثبات (Consistency): در Realm تمام تغییرات با یک schema اعتبارسنجی می شود.
  • جداسازی (Isolation): در Realm تنها یک عملیات مجوز نوشتن در یک زمان را دارد.
  • پایداری(Durability): در Realm ذخیره فوری هر تغییر در دیسک را داریم.

برای شروع استفاده از Realm، یادگیری برخی مفاهیم برای درک نحوه عملکرد آن مهم است.

درک Realm

Realm ، مجموعه ای از آبجکت های مرتبط است که schema ای از پیش تعریف شده دارند. شما می توانید چندین Realm در یک برنامه داشته باشید. هر Realm می‌تواند مجوزهای متفاوتی داشته باشد و می‌تواند شامل انواع داده‌ها یا آبجکت مختلف باشد.

schema مجموعه ای از قوانین(rule) است که انواع داده هایی را که دیتابیس می تواند ذخیره کند را تعریف می کند. شما این schema را به عنوان مجموعه ای از فیلدها و انواع داده های آنها در یک یا چند آبجکت به نام Realm objects تعریف می کنید.

یک Realm object داده ها را از دیتابیس می خواند و می نویسد. دیتابیس این آبجکت ها را حفظ می کند. آنها همیشه حاوی آخرین مقادیر هستند.

هر schema یک نسخه (version) دارد. تغییر در schema شامل افزودن یا حذف یک فیلد یا افزودن یک realm object جدید است. شما باید نسخه schema را افزایش دهید و یک migration ایجاد کنید تا به دیتابیس بگویید چه چیزی در schema تغییر کرده است.

اکنون که این مفاهیم بیسیک را می‌دانید، زمان شروع استفاده از Realm است. در بخش زیر، Realm را به پروژه اضافه خواهید کرد.

راه اندازی Realm

فایل build.gradle پروژه را باز کنید. در بخش dependencies ، خط زیر را بعد از وابستگی navigation-safe-args-gradle-plugin اضافه کنید:

 classpath "io.realm:realm-gradle-plugin:10.9.0" 

فایل build.gradle ماژول را برای اعمال plugin باز کنید. بعد از آخرین plugin ، خط زیر را اضافه کنید:

 plugins {     …………     …………     id: 'realm-android' } 

برای همگام سازی(synchronize) پروژه، روی sync کلیک کنید. پس از تکمیل همگام‌سازی، PetApplication.kt را باز کنید و خط زیر را در onCreate() اضافه کنید و io.realm.Realm را import کنید:

 Realm.init(this) 

این خط Realm را مقداردهی اولیه می کند و آن را در سراسر برنامه در دسترس قرار می دهد. اکنون می توانید یک نمونه از Realm دریافت کنید و شروع به اضافه کردن object ها و ایجاد پرس و جو(query) کنید.
Realm همچنین برای راه اندازی دیتابیس به RealmConfiguration نیاز دارد. PetsModule.kt را از طریق پکیج di باز کنید و کد زیر را با وارد کردن io.realm.RealmConfiguration ، import کنید:

 // 1. private val realmVersion = 1L  @Singleton @Provides fun providesRealmConfig(): RealmConfiguration =   // 2.   RealmConfiguration.Builder()     .schemaVersion(realmVersion)     .build() 

PetRealm از دو موجودیت استفاده می کند: حیوانات خانگی(pets) و صاحبان(owners). این موجودیت ها schema های دیتابیس را ایجاد می کنند. نمودار زیر این دو موجودیت را به همراه فیلدهایشان نشان می دهد.

هر دو موجودیت دارای شناسه ای(id) برای شناسایی هر عنصر هستند، بنابراین آن را به کلید اصلی(primary key) تبدیل می کنند. همانطور که می بینید، ترکیبی از انواع داده های String، int و boolean، و همچنین فیلدهای NULL و NOT NULL وجود دارد. شما باید این اطلاعات را در هر realm object تعریف کنید.

توجه: Realm از انواع مختلفی از فیلدها پشتیبانی می کند. برای فهرست کامل این فیلدها، به documentation رسمی مراجعه کنید.

ابتدا آبجکت pet را ایجاد خواهید کرد. در پکیج realm یک کلاس جدید ایجاد کنید و نام آن را PetRealm.kt بگذارید. کد زیر را اضافه کنید:

 // 1. open class PetRealm( @PrimaryKey // 2. var id: String = ObjectId().toHexString(), // 3. @Required // 4. var name: String = "", @Required var petType: String = "", var age: Int = 0, var isAdopted: Boolean = false, @DrawableRes var image: Int? = null // 5. ): RealmObject() // 6. 

ابتدا androidx.annotation.DrawableRes، سپس io.realm.RealmObject، سپس io.realm.annotations.PrimaryKey، سپس io.realm.annotations.Required و org.bson.types.ObjectId را import کنید.

اینجا چند چیز در جریان است:

  1. شما باید هر موجودیت را به صورتclass open و هر فیلد را var تعریف کنید.
  2. @PrimaryKey نشان می دهد که فیلد ID ، کلید اصلی است.
  3. Realm،ObjectId() را برای ایجاد شناسه های منحصر به فرد برای هر شی فراهم می کند.
  4. @Required نشان می دهد که فیلد به یک مقدار نیاز دارد. این annotation را به name و petType اضافه کنید.
  5. برای فیلدهایی که مقادیر null را مجاز می کنند، می توانید از nullable استفاده کنید و null را به عنوان مقدار پیش فرض آن اختصاص دهید.
  6. هر موجودیت باید یک RealmObject() باشد.

یک کلاس در پکیج realm ایجاد کنید و نام آن را OwnerRealm.kt بگذارید. کد زیر را اضافه کنید:

 open class OwnerRealm( @PrimaryKey var id: String = ObjectId().toHexString(), @Required var name: String = "", @DrawableRes var image: Int? = null ) : RealmObject() 

ابتدا androidx.annotation.DrawableRes، سپس io.realm.RealmObject، سپس io.realm.annotations.PrimaryKey، سپس io.realm.annotations.Required و در نهایت org.bson.types.ObjectId را import کنید.با این کد، موجودیت OwnerRealm را به دیتابیس Realm اضافه می کنید.برنامه را build و run کنید. در پشت صحنه، Realm PetRealm و OnwerRealm را به schema اضافه می کند. با این حال، همچنان یک صفحه خالی خواهید دید.

اکنون که schema را ایجاد کرده اید، زمان درج چند آبجکت است.درج Object ها در Realmدرج آبجکت ها در دیتابیس بخشی از تراکنش های نوشتن Realm است. تمام عملیات باید در یک تراکنش انجام شود. تراکنش گروهی از عملیات خواندن و نوشتن است که Realm به صورت یک عملیات واحد اجرا می کند. هر عملیات در تراکنش باید موفقیت آمیز باشد تا تراکنش با موفقیت انجام شود. اگر هر عملیاتی با شکست مواجه شود، کل تراکنش با شکست مواجه می شود.فایل PetDatabaseOperations.kt را در پکیج realm باز کنید. پارامتر زیر را به سازنده کلاس اضافه کنید:private val config: RealmConfigurationبا این خط، RealConfiguration را به این کلاس ارائه می دهید.

insertPet() را به صورت زیر تغییر دهید:

 suspend fun insertPet(name: String, age: Int, type: String, image: Int?) { // 1. val realm = Realm.getInstance(config)  // 2. realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction -> // 3. val pet = PetRealm(name = name, age = age, petType = type, image = image) // 4. realmTransaction.insert(pet) } } 

ابتدا io.realm.Realm، و سپس io.realm.kotlin.executeTransactionAwait و kotlinx.coroutines.Dispatchers را import کنید.

در این کد شما:

با استفاده از RealmConfiguration یک نمونه(instance) از Realm دریافت کنید.

از executeTransactionAwait() به همراه Dispatchers.IO برای اجرای تراکنش در یک background thread استفاده کنید و منتظر بمانید تا پایان یابد.

یک آبجکت جدید PetRealm ایجاد کنید.

آبجکت جدید PetRealm را Insert کنید.

بسیار مهم است که از نمونه(instance) Realm، به نام realmTransaction در کد بالا، که در lambda function برای درج (insert) شی جدید ایجاد شده، استفاده کنید.

برنامه را Build و run کنید. دکمه add petرا فشار دهید و یک حیوان خانگی (pet) جدید به شرح زیر اضافه کنید:

Add Pet را فشار دهید و حیوان خانگی جدید را به دیتابیس وارد خواهید کرد. در این مورد باید به من اعتماد کنید، زیرا برنامه هنوز چیزی را نمایش نمی دهد.

کد را برای درج مالک(owner) اضافه کنید. OwnerDatabaseOperations.kt را باز کنید و پارامتر زیر را به سازنده آن اضافه کنید:

  private val config: RealmConfiguration 

این خط RealmConfiguration را برای این کلاس فراهم می کند.

insertOwner() را به صورت زیر تغییر دهید:

 suspend fun insertOwner(name: String, image: Int?) {   // 1.   val realm = Realm.getInstance(config)   // 2.   realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     // 3.     val owner = OwnerRealm(name = name, image = image)     // 4.     realmTransaction.insert(owner)   } } 

این کد ، مشابه مراحل افزودن حیوان خانگی(adding a pet) می باشد:

  • یک نمونه(instance) از Realm دریافت کنید
  • .از executeTransactionAwait() استفاده کنید.
  • آبجکت جدید را ایجاد کنید.
  • آن را در پایگاه داده قرار دهید.

برنامه را Build و run کنید. دکمه Owners را فشار دهید. یک نام اضافه کنید و یک تصویر را طولانی(long press) فشار دهید تا آن را انتخاب کنید، به شرح زیر:

Add owner را فشار دهید و باید دوباره به من اعتماد کنید.

نگران نباشید مرحله بعدی ، نحوه پرس و جو(Query) از دیتابیس و نمایش اطلاعات را یاد خواهید گرفت.

Query در Realm

Realm یک موتور پرس و جو(query engine) ارائه می دهد که به شما امکان می دهد آبجکت ها را پیدا، فیلتر و مرتب کنید. هر نتیجهquery یک live object است. این بدان معنی است که حاوی آخرین داده ها است و اگر تصمیم به تغییر نتیجه داشته باشید، آبجکت ذخیره شده را تغییر می دهد.

PetDatabaseOperations.kt را باز کنید. کد زیر را در پایان کلاس اضافه کنید:

 private fun mapPet(pet: PetRealm): Pet {   return Pet(     name = pet.name,     age = pet.age,     image = pet.image,     petType = pet.petType,     isAdopted = pet.isAdopted,     id = pet.id   ) } 

mapPet() شی PetRealm را به شی Pet UI ، map می کند.

retrievePetsToAdopt() را به روش زیر تغییر دهید:

 suspend fun retrievePetsToAdopt(): List<Pet> {   // 1.   val realm = Realm.getInstance(config)   val petsToAdopt = mutableListOf<Pet>()    // 2.   realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     petsToAdopt.addAll(realmTransaction       // 3.       .where(PetRealm::class.java)       // 4.       .findAll()       // 5.       .map {         mapPet(it)       }     )   }   return petsToAdopt }  

برای بازیابی (retrieve) حیوانات خانگی جهت فرزندخواندگی، باید شما:

  1. نمونه(instance) Realm را دریافت کنید.
  2. از executeTransactionAwait() استفاده کنید.
  3. از Where(PetRealm::class.java) برای بازیابی اشیاء PetRealm استفاده کنید.
  4. findAll() کوئری را اجرا می کند و هر آبجکت، PetRealm را برمی گرداند.
  5. Map کردن PetRealm به آبجکت pet.

OwnerDatabaseOperations.kt را باز کنید و retrieveOwners() را به صورت زیر تغییر دهید:

 suspend fun retrieveOwners(): List<Owner> {   // 1.   val realm = Realm.getInstance(config)   val owners = mutableListOf<Owner>()    // 2.   realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     owners.addAll(realmTransaction       // 3.       .where(OwnerRealm::class.java)       // 4.       .findAll()       // 5.       .map { owner ->         Owner(           name = owner.name,            image = owner.image,            id = owner.id         )       }     )   }   return owners } 

برای بازیابی(retrieve) مالکان، شما:

نمونه(instance) Realm را دریافت کنید.

از executeTransactionAwait() استفاده کنید.

از Where(OwnerRealm::class.java) برای بازیابی آبجکت OwnerRealm استفاده کنید.

findAll() کوئری را اجرا می کند.

Map کردن OwnerRealm به آبجکت Owner.

اکنون برنامه را build و run کنید. حیوانات خانگی را که قبلا اضافه کرده اید می بینید. اگر به صفحه Owners بروید، مالکی (owner)را که اضافه کرده‌اید نیز می‌بینید:

اکنون می توانید داده های دیتابیس را مشاهده کنید. با این حال، یک اشکال وجود دارد، و شما می توانید چندین بهینه سازی را ایجاد کنید.

فیلتر کردن نتایج

اشکال در بازیابی حیوانات خانگی این است که پرس و جوی هر حیوان خانگی را، چه پذیرفته شده و چه در زمان پذیرش، برمی گرداند. اما Realm اپراتورهای فیلتری را ارائه می دهد که به فیلتر کردن نتایج بر اساس مقادیر خاص کمک می کند.

در PetDatabaseOperations.kt، retrievePetsToAdopt() را با افزودن خط زیر بعد از (.where) تغییر دهید:

 .equalTo("isAdopted", false) 

این عملیات فقط مواردی از PetRealm را که به عنوان نادرست پذیرفته شده اند برمی گرداند.

اکنون retrieveAdoptedPets() را مانند خط زیر تغییر دهید:

 suspend fun retrieveAdoptedPets(): List<Pet> {   val realm = Realm.getInstance(config)   val adoptedPets = mutableListOf<Pet>()    realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     adoptedPets.addAll(realmTransaction       .where(PetRealm::class.java)       .equalTo("isAdopted", true)       .findAll()       .map {         mapPet(it)       }     )   }   return adoptedPets } 

برای بازیابی حیوانات خانگی پذیرفته شده، isAdopted باید true باشد.

اکنون می توانید فیلتر را بر اساس نوع حیوان خانگی در لیست “Pets to adopt” پیاده سازی کنید. retrieveFilteredPets() را به صورت زیر تغییر دهید:

 suspend fun retrieveFilteredPets(petType: String): List<Pet> {   val realm = Realm.getInstance(config)   val filteredPets = mutableListOf<Pet>()    realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     filteredPets.addAll(realmTransaction       .where(PetRealm::class.java)       // 1.       .equalTo("isAdopted", false)       // 2.       .and()       // 3.       .beginsWith("petType", petType)       .findAll()       .map {         mapPet(it)       }     )   }   return filteredPets } 

این کد یک تراکنش را برای بازیابی آبجکت های PetRealm اجرا می کند. فیلتر به روش زیر عمل می کند:

  1. شرط فیلتر ، آبجکت های PetRealm که به عنوان نادرست پذیرفته شده اند.
  2. and() یک عملگر منطقی است که نشان می دهد نتیجه باید هر دو شرط را داشته باشد.
  3. شرط فیلتر کردن آبجکت های PetRealm که فیلد petType خود را با مقدار ارائه شده دارند.

پس از اجرای کوئری و mapping نتایج آبجکت Pet، متد ، لیستی از حیوانات خانگی petType انتخاب شده را return می کند.

برنامه را بسازید و اجرا کنید. همانطور که در تصویر بعدی نشان داده شده است، انواع مختلف حیوانات خانگی را به لیست اضافه کنید:.

یک نوع حیوان خانگی را از spinner بالا انتخاب کنید:

عالی! شما bug را برطرف کرده اید و عملکرد filtering را اجرا کرده اید. اکنون، می توانید یک بهینه سازی جزئی به لیست مالکان اضافه کنید.

مرتب سازی نتایج

گاهی اوقات باید نتایج کوئری ها را قبل از نمایش آنها روی صفحه مرتب کنید. به OwnerDatabaseOperations.kt بروید و خط زیر را به query در retrieveOwners() بعد از findAll() اضافه کنید:

 .sort("name", Sort.ASCENDING) 

io.realm.Sort، را import کنید.
این عملیات نتایج را بر اساس فیلد نام به ترتیب صعودی مرتب می کند.برنامه را build و run کنید. ownerهای دیگر را به لیست اضافه کنید. مانند تصویر زیر، ownerها را می بینید که بر اساس نام مرتب شده اند:

هر owner تعداد حیوانات خانگی (pet) خود را نشان می دهد، اما ، این تعداد همیشه صفر است. چگونه می توانید تعداد حیوانات خانگی را با استفاده از Realm بدست آورید؟

انجام محاسبات

مقدار دیگری که باید نمایش دهید تعداد حیوانات خانگی است که هر صاحب آن دارد. Realm عملگرهای مجموع(aggregate) مختلفی دارد. این عملگرها لیستی از آبجکت های Realm را پیمایش می کنند و مقداری را محاسبه می کنند.

 OwnerDatabaseOperations.kt را باز کنید و کد زیر را اضافه کنید:  private fun getPetCount(realm: Realm, ownerId: String): Long {   // 1.   return realm.where(PetRealm::class.java)     // 2.     .equalTo("owner.id", ownerId)     // 3.     .count() } 

در این کد شما:

کوئری برای دریافت آبجکت PetRealm.

از owner.id برای فیلتر کردن بر اساس شناسه owner(مالک) استفاده کنید.

با استفاده از count() تعداد حیوانات خانگی یک owner را بشمارید.

ایجاد Owner را در retrieveOwners() برای اضافه کردن numberOfPets به صورت زیر تغییر دهید:

 Owner(   name = owner.name,   image = owner.image,   id = owner.id,   numberOfPets = getPetCount(realmTransaction, owner.id) ) 

شما اکنون حیوانات خانگی و مالک ها (owner) را دارید. زمان آن فرا رسیده است که به هر owner(مالک) چند حیوان خانگی داشته باشد.

افزودن روابط(Relationship)

Realm راهی برای پیاده سازی روابط یک به یک، یک به چند و معکوس ارائه می دهد.

تعریف روابط یک به یک

رابطه یک به یک زمانی است که یک آبجکت حداکثر با یک نمونه از یک آبجکت دیگر ارتباط داشته باشد. همانطور که در نمودار زیر نشان داده شده است، در PetRealm، این اتفاق برای حیوان خانگی که حداکثر می تواند یک صاحب داشته باشد، رخ می دهد:

PetRealm.kt را باز کنید و پارامتر زیر را به سازنده کلاس اضافه کنید:

var owner: OwnerRealm? = nullاین خط به آبجکت PetRealm می گوید که می تواند حداکثر یک OwnerRealm داشته باشد. اما رابطه دیگری در این دیتابیس وجود دارد: یک مالک می تواند چندین حیوان خانگی داشته باشد.

تعریف روابط یک به چند

رابطه یک به چند زمانی است که یک آبجکت به چندین آبجکت مربوط می شود. این سناریویی است که یک مالک می تواند چندین حیوان خانگی داشته باشد، همانطور که در نمودار زیر نشان داده شده است:

OwnerRealm.kt را باز کنید و پارامتر زیر را به سازنده کلاس اضافه کنید:

 var pets: RealmList<PetRealm> = RealmList() 

io.realm.RealmList را import کنید.

RealmList به OwnerRealm اجازه می دهد تا با PetRealm رابطه یک به چند داشته باشد.

آفرین! شما دو رابطه را در PetRealm پیاده سازی کرده اید. با این حال، Realm نوع سومی از رابطه را ارائه می دهد.

استفاده از روابط معکوس(Inverse Relationships)

روابطی که اجرا کردید یک طرفه هستند. این بدان معناست که وقتی نتایج کوئری را برای حیوانات خانگی دریافت می کنید، صاحبان آنها در نتایج در دسترس نخواهند بود. این کمی مشکل است، زیرا شما باید صاحب حیوان خانگی را در لیست حیوانات خانگی پذیرفته شده نشان دهید.

Realm برای حل این موضوع روابط معکوس ارائه می دهد. به PetRealm.kt بروید و پارامتر owner را در سازنده با خطوط زیر جایگزین کنید:

 @LinkingObjects("pets") // 1. val owner: RealmResults<OwnerRealm>? = null // 2. 

io.realm.annotations.LinkingObjects و io.realm.RealmResults را import کنید.

برای اضافه کردن یک رابطه معکوس، باید:

  • انوتیشن LinkingObjects@ را اضافه کنید و نام فیلدی را که رابطه را به آن اضافه می کنید به عنوان پارامتر ارسال کنید. فیلدی در OwnerRealm که می‌خواهید پیوند دهید pet است.
  • فیلد باید val و از نوع RealmResults باشد.
  • اکنون می توانید اطلاعات OwnerRealm را در کوئری PetRealm دریافت کنید.

زمان ساخت و اجرای برنامه فرا رسیده است. با نگاهی به Logcat، خطای زیر را خواهید دید:

 Process: com.raywenderlich.android.petrealm, PID: 16049 	io.realm.exceptions.RealmMigrationNeededException: Migration is required due to the following errors: 	- Property 'OwnerRealm.pets' has been added. 

پس از افزودن فیلدهای جدید، باید یک migration ایجاد کنید تا به دیتابیس بگویید چه چیزی تغییر کرده است.Migrating دیتابیس

Realm هر حالت از شمای(schema) دیتابیس را به یک ورژن خاص نگاشت (map) می کند. اگر این schema تغییر کند، مانند زمانی که روابط را در بخش قبلی اضافه کردید، ورژن باید افزایش یابد. همچنین باید به Realm بگویید که چگونه با ایجاد یک Migrating ، تفاوت‌های موجود در schema را مدیریت کند.

یک فایل جدید در پکیج realm ایجاد کنید و نام آن را Migrations.kt بگذارید. کد زیر را اضافه کنید:

 // 1. val migration = RealmMigration { realm, oldVersion, newVersion ->   // 2.   if (oldVersion == 1L) { // 3.     val ownerSchema = realm.schema.get("OwnerRealm")     val petSchema = realm.schema.get("PetRealm")      // 4.     petSchema?.let {       ownerSchema?.addRealmListField("pets", it)     }   } } 

io.realm.RealmMigration را import کنید.

برای اضافه کردن یک Migrating ، باید:

  1. یک val از نوع RealmMigration ایجاد کنید.
  2. تعریف کنید که برای هر تغییر ورژن چه کاری باید انجام دهید. oldVersion مقدار نسخه schema قبلی را نگه می دارد.
  3. هر schema را که باید اصلاح کنید دریافت کنید.
  4. ownerSchema به یک فیلد RealmList جدید از نوع PetRealm نیاز دارد. از addRealmListField() با نام فیلد و نوع schema مورد نیاز فیلد استفاده کنید.

PetsModule.kt را در پکیج di باز کنید. ورژن schema را به این صورت افزایش دهید:

 private val realmVersion = 2L 

providesRealmConfig() را به صورت زیر تغییر دهید:

 RealmConfiguration.Builder()   .schemaVersion(realmVersion)   .migration(migration)   .build() 

از migration() برای اضافه کردن migration استفاده کنید. اگر برنامه را build و run کنید، دوباره اجرا می شود. همه چیز همانطور که انتظار می رود کار می کند زمان مهم ترین مرحله است: پذیرش حیوانات خانگی.

به روز رسانی آبجکت

برای به‌روزرسانی آبجکت های Realm، باید آبجکت مورد نظر خود را به‌روزرسانی کنید و مقادیر جدید را تعیین کنید.

برای پذیرفتن حیوان خانگی، isAdopted باید به true تغییر کند و حیوان خانگی به صاحبش اختصاص یابد. OwnerDatabaseOperations.kt را باز کنید و updatePets() را مانند زیر تغییر دهید:

  suspend fun updatePets(petId: String, ownerId: String) {   val realm = Realm.getInstance(config)    // 1.   realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     // 2.     val pet = realmTransaction       .where(PetRealm::class.java)       .equalTo("id", petId)       .findFirst()      // 3.     val owner = realmTransaction       .where(OwnerRealm::class.java)       .equalTo("id", ownerId)       .findFirst()      // 4.     pet?.isAdopted = true     // 5.     owner?.pets?.add(pet)   } } 

در این کد شما:

  1. یک تراکنش برای اجرای عملیات نوشتن اضافه کنید.
  2. کوئری برای حیوان خانگی خوش شانس
  3. کوئری برای صاحبی که حیوان خانگی را قبول می کند.
  4. به روز رسانی کردن مقدار isAdopted
  5. حیوان خانگی را به لیست حیوانات خانگی آن مالک اضافه کنید.

PetDatabaseOperations.kt را باز کنید و mapPet() را به صورت زیر تغییر دهید:

 private fun mapPet(pet: PetRealm): Pet {   return Pet(     name = pet.name,     age = pet.age,     image = pet.image,     petType = pet.petType,     isAdopted = pet.isAdopted,     id = pet.id,     ownerName = pet.owner?.firstOrNull()?.name   ) } 

می‌توانید از روابطی که قبلاً اضافه کرده‌اید استفاده کنید و نام مالک را به هر حیوان خانگی به عنوان فرزندخواندگی اضافه کنید.

برنامه را build و run کنید. گزینه Adopt Me را در هر حیوان خانگی فشار دهید و صاحب آن را انتخاب کنید. یک مالک واحد برای پذیرش چندین حیوان خانگی ایجاد کنید. به صفحه Adopted Pets بروید و حیوانات خانگی خوش شانس را خواهید دید:

صفحه مربوط به Owners را باز کنید. می‌توانید تعداد حیوانات خانگی که هر صاحب آن را پذیرفته است را ببینید.

با این حال، ممکن است مواقعی پیش بیاید که حیوان خانگی فرار کند یا صاحبش دیگر علاقه ای به فرزندخواندگی نداشته باشد. در این صورت، باید بتوانید آنها را از برنامه حذف کنید.

حذف اشیاء

PetDatabaseOperations.kt را باز کنید و removePet() را به صورت زیر تغییر دهید:

 suspend fun removePet(petId: String) {   val realm = Realm.getInstance(config)   realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     // 1.     val petToRemove = realmTransaction       .where(PetRealm::class.java)       .equalTo("id", petId)       .findFirst()     // 2.     petToRemove?.deleteFromRealm()   } } 

برای حذف یک آبجکت باید:

کوئری برای آبجکتی که می خواهید حذف کنید، ایجاد کنید. این کوئری باید در یک تراکنش باشد.

در آن آبجکت ، از deleteFromRealm()برای حذف آن از دیتابیس استفاده کنید.

حذف آبجکت هایی که رابطه دارند نیاز به یک مرحله اضافی دارد. OwnerDatabaseOperations.kt را باز کنید و removeOwner() را مانند زیر به روز کنید:

 suspend fun removeOwner(ownerId: String) {   val realm = Realm.getInstance(config)    realm.executeTransactionAwait(Dispatchers.IO) { realmTransaction ->     // 1.     val ownerToRemove = realmTransaction       .where(OwnerRealm::class.java)       .equalTo("id", ownerId)       .findFirst()       // 2.       ownerToRemove?.pets?.deleteAllFromRealm()       // 3.       ownerToRemove?.deleteFromRealm()   } } 

شما باید:

  1. کوئری برای مالکی که می خواهید حذف کنید.
  2. از deleteAllFromRealm() برای حذف همه حیوانات خانگی که صاحب دارد استفاده کنید.
  3. در نهایت، آبجکت مالک را حذف کنید.

برنامه را build و run کنید و برخی از حیوانات خانگی و صاحبان را حذف کنید. می‌توانید ببینید که اگر مالک را حذف کنید، حیوانات خانگی از مالک حذف می‌شوند.

اکنون، PetRealm کامل شده است. با این حال، چگونه می توانید داده ها را در دیتابیس Realm اشکال زدایی(debug) کنید؟

با استفاده از Realm Studio

Realm Studio یک visual tool است که به شما کمک می کند دیتابیس Realm را مشاهده، ویرایش و ایجاد کنید. به وب سایت Realm Studio بروید و نسخه 11.1.0 را دانلود و نصب کنید.

در Android Studio به View ▸ Windows Tool ▸ Device File Explorer بروید. شبیه ساز مورد استفاده خود را از منوی کشویی انتخاب کنید. به فایل های data ▸ data ▸ com.raywenderlich.android.petrealm ▸ بروید. در اینجا، می توانید دیتابیس با نام default.realm را همانطور که در تصویر بعدی نشان داده شده است پیدا کنید:

روی نام فایل Realm کلیک راست کرده و Save As را انتخاب کنید. یک مکان در رایانه خود انتخاب کنید و فایل را ذخیره کنید. اکنون Realm Studio را باز کرده و Open Realm file را فشار دهید. به فایل ذخیره شده بروید و آن را انتخاب کنید. ابتدا شمای OwnerRealm را خواهید دید:

در آن می توانید مقادیر فعلی ID ، نام، تصویر و حیوانات خانگی را مشاهده کنید. همانطور که می بینید، value حیوانات خانگی لیستی از ID های حیوانات خانگی است.

PetRealm را در نوار کناری سمت چپ انتخاب کنید و موارد زیر را مشاهده خواهید کرد:

روی Create PetRealm در بالا سمت راست کلیک کنید و حیوان خانگی زیر را اضافه کنید:

روی Create کلیک کنید تا حیوان خانگی جدید را به دیتابیس اضافه کنید.

عملیات دیگری که می توانید در Realm Studio انجام دهید عبارتند از:

  • ایجاد کلاس های جدید
  • افزودن property به کلاس های موجود
  • کوئری در کلاس ها

اکنون که با Realm آشنا شدید، وقت آن است که در مورد Room، یکی از محبوب‌ترین کتابخانه‌های پایدار اندروید صحبت کنیم. تفاوت Room و Realm چیست؟

مقایسه Realm با Room

Jetpack ، Room را فراهم می کند، یک کتابخانه پایدار داده که از SQLite در پشت صحنه استفاده می کند.

شما می توانید فقط انواع و رشته های primitive را در Room ذخیره کنید. می توانید از type converterها برای تبدیل یک آبجکت به انواع primitive و ذخیره آن در دیتابیس استفاده کنید. به عنوان مثال، اگر شما نیاز به ذخیره یک تاریخ دارید، ابتدا باید آن را به Long تبدیل کنید.

Room به آبجکت موجودیت اجازه نمی دهد به یکدیگر ارجاع دهند. این بدان معناست که وقتی با روابط (relationship)کار می‌کنید، باید کلاس‌های میانی برای مدل‌سازی این روابط بین موجودیت‌ها ایجاد کنید.

از سوی دیگر، Realm خود ماندگاری آبجکت را کنترل می کند. این بدان معناست که شما می توانید انواع primitive ، رشته ها و هر نوع آبجکت و لیست را ذخیره کنید. هر آبجکت باید یک نمونه از RealmObject باشد.

همانطور که در بخش روابط یاد گرفتید، می توانید از یک رابطه معکوس برای بدست آوردن داده های موجودیت مرتبط استفاده کنید. برای به دست آوردن اطلاعات مورد نیاز ، نیازی به انجام چندین کوئری ندارید.

Realm دارای توابع پیشرفته دیگری مانند:

  • ایجاد Realm Apps برای همگام سازی داده ها در زمان واقعی بین سیستم عامل های مختلف.
  • استفاده از App Services برای احراز هویت و مدیریت مجوزها.
  • کار یکپارچه با MongoDB.

سخن پایانی

پایگاه داده Realm به شما امکان می دهد آبجکت ها را به صورت محلی ذخیره کرده و به آنها دسترسی داشته باشید. می توانید داده ها را وارد کنید، پرس و جو کنید، نتایج را فیلتر و مرتب کنید، آبجکت ها را به روز کنید و حذف کنید. همچنین یک راه ساده برای ایجاد روابط بین موجودیت ها ارائه می دهد.

امیدوارم از این آموزش در Realm لذت برده باشید.

نوشته دیتابیس Realm در اندروید اولین بار در آموزشگاه اندروید ایران. پدیدار شد.

توسط asadroid

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *