Room, temel ve kutulanmış türleri dönüştürebilir ancak nesne referanslarına izin vermez. Tür dönüştürücüleri kullanmayı ve Room'un neden nesne referanslarını desteklemediğini öğrenin.
Tür dönüştürücüleri kullanma
Bazen uygulamanızın özel bir veri türünü tek bir veritabanı sütununda saklaması gerekir. Tür dönüştürücüler sağlayarak özel türleri desteklersiniz. Bunlar, Room'a özel türleri Room'un kalıcı hale getirebileceği bilinen türlere ve bilinen türlerden nasıl dönüştüreceğini söyleyen işlevlerdir. Tür dönüştürücüleri @ColumnTypeConverter ek açıklamasını kullanarak tanımlarsınız.
Room veritabanınızda Date örneklerini kalıcı hale getirmeniz gerektiğini varsayalım. Room, Date nesnelerini yerel olarak kalıcı hale getiremez. Bu nedenle, tür dönüştürücüleri tanımlamanız gerekir:
object Converters { @ColumnTypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(it) } } @ColumnTypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time } }
Bu örnekte iki tür dönüştürücü işlevi tanımlanmaktadır: biri Date nesnesini Long nesnesine, diğeri ise Long nesnesini tekrar Date nesnesine dönüştürür. Room, Long nesnelerini kalıcı hale getirebildiğinden Date nesnelerini kalıcı hale getirmek için bu dönüştürücüleri kullanabilir.
Ardından, Room'un tanımladığınız dönüştürücü sınıfını kullanabilmesi için AppDatabase sınıfına @ColumnTypeConverters ek açıklamasını ekleyin:
@Database(entities = [User::class], version = 1) @ColumnTypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
Bu tür dönüştürücüler tanımlandığında, özel türünüzü varlıklarınızda ve DAO'larınızda temel türleri kullandığınız gibi kullanabilirsiniz:
@Entity data class User( @PrimaryKey val id: Long, val name: String, val birthday: Date? ) @Dao interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") suspend fun findUsersBornOnDate(targetDate: Date): List<User> }
Bu örnekte AppDatabase öğesini @ColumnTypeConverters ile ek açıklama olarak eklediğiniz için Room, tanımlanan tür dönüştürücüyü her yerde kullanabilir. Dönüştürücüleri belirli varlıklar veya DAO'lar ile sınırlamak için @Entity ya da @Dao sınıflarınızı @ColumnTypeConverters ile açıklama ekleyin.
Kontrol türü dönüştürücü başlatma
Normalde Room, tür dönüştürücüleri sizin için başlatır. Ancak tür dönüştürücü sınıflarınıza ek bağımlılıklar iletmeniz gerekiyorsa uygulamanız bunların başlatılmasını doğrudan kontrol etmelidir. Bu durumda, dönüştürücü sınıfınıza @ProvidedColumnTypeConverter ile ek açıklama ekleyin:
@ProvidedColumnTypeConverter class ExampleConverter { @ColumnTypeConverter fun stringToExample(string: String?): ExampleType? { return string?.let { ExampleType() } } @ColumnTypeConverter fun exampleToString(example: ExampleType?): String? { return example?.toString() } }
Dönüştürücü sınıfınızı @ColumnTypeConverters içinde tanımlamanın yanı sıra, dönüştürücü sınıfınızın bir örneğini RoomDatabase oluşturucuya iletmek için RoomDatabase.Builder.addColumnTypeConverter işlevini kullanın:
val db = Room.databaseBuilder<MyDatabase>(applicationContext, "database-name") .addColumnTypeConverter(exampleConverterInstance) .build()
Room'un neden nesne referanslarına izin vermediğini anlama
Önemli nokta: Room, varlık sınıfları arasında nesne referanslarına izin vermez. Bunun yerine, uygulamanızın ihtiyaç duyduğu verileri açıkça istemeniz gerekir.
Bir veritabanındaki ilişkileri ilgili nesne modeline eşlemek yaygın bir uygulamadır ve sunucu tarafında çok iyi sonuç verir. Program, özelliklere erişildikçe bunları yüklese bile sunucu iyi performans göstermeye devam eder.
Ancak bu tür geç yükleme, genellikle kullanıcı arayüzü iş parçacığında gerçekleştiği ve kullanıcı arayüzü iş parçacığında diskteki bilgilerin sorgulanması önemli performans sorunlarına yol açtığı için istemci tarafında mümkün değildir. Kullanıcı arayüzü iş parçacığı, bir etkinliğin güncellenen düzenini hesaplamak ve çizmek için genellikle yaklaşık 16 ms'ye sahiptir. Bu nedenle, bir sorgu yalnızca 5 ms sürse bile uygulamanızın kareyi çizmek için zamanı tükenmesi ve gözle görülür görsel hatalara neden olması olasıdır. Paralel olarak çalışan ayrı bir işlem varsa veya cihazda diski yoğun kullanan başka görevler çalışıyorsa sorgunun tamamlanması daha da uzun sürebilir. Ancak tembel yükleme kullanmıyorsanız uygulamanız gerekenden daha fazla veri getirir ve bu da bellek tüketimi sorunlarına yol açar.
Nesne-ilişkisel eşlemeler genellikle bu kararı geliştiricilere bırakır. Böylece geliştiriciler, uygulamalarının kullanım alanları için en iyi olanı yapabilir. Geliştiriciler genellikle modeli uygulamaları ve kullanıcı arayüzü arasında paylaşmaya karar verir. Ancak bu çözüm iyi ölçeklenmez. Çünkü kullanıcı arayüzü zaman içinde değiştiğinde paylaşılan model, geliştiricilerin tahmin etmesi ve hata ayıklaması zor olan sorunlar oluşturur.
Örneğin, her bir kitap için bir Author nesnesi bulunan Book nesnelerinin listesini yükleyen bir kullanıcı arayüzü düşünün. Başlangıçta, Book örneklerinin yazarı alması için sorgularınızı geç yüklemeyi kullanacak şekilde tasarlayabilirsiniz. author özelliğiyle ilgili ilk alma işlemi, veritabanına sorgu gönderir. Bir süre sonra, yazar adını uygulamanızın kullanıcı arayüzünde de göstermeniz gerektiğini fark ediyorsunuz. Bu ada aşağıdaki kod snippet'inde gösterildiği gibi erişebilirsiniz:
Text(text = book.author.name)
Ancak bu masum gibi görünen değişiklik, Author tablosunun ana iş parçacığında sorgulanmasına neden olur.
Yazar bilgilerini önceden sorgularsanız ancak bu bilgilere ihtiyacınız yoksa verilerin nasıl yüklendiğini değiştirmek zor olur. Örneğin, uygulamanızın kullanıcı arayüzünde artık Author bilgilerinin gösterilmesi gerekmiyorsa uygulamanız, göstermediği verileri yükleyerek değerli bellek alanını boşa harcar. Author sınıfı, Books gibi başka bir tabloya referans veriyorsa uygulamanızın verimliliği daha da düşer.
Room'u kullanarak aynı anda birden fazla öğeye referans vermek için her öğeyi içeren bir veri nesnesi oluşturun ve ardından ilgili tabloları birleştiren bir sorgu yazın. Bu iyi yapılandırılmış model, Room'un güçlü sorgu doğrulama özellikleriyle birlikte uygulamanızın veri yüklerken daha az kaynak tüketmesini sağlayarak uygulamanızın performansını ve kullanıcı deneyimini iyileştirir.