SQLite ilişkisel bir veritabanı olduğundan, öğeler arasındaki ilişkileri tanımlayabilirsiniz. Ancak çoğu nesne-ilişkisel eşleme kitaplığı, varlık nesnelerinin birbirine referans vermesine izin verirken Room bunu açıkça yasaklar. Bu kararın arkasındaki teknik gerekçeyi öğrenmek için Room'un neden nesne referanslarına izin vermediğini anlama başlıklı makaleyi inceleyin.
İlişki türleri
Room, aşağıdaki ilişki türlerini destekler:
- Bire bir: Tek bir varlığın başka bir tek varlıkla ilişkili olduğu durumu ifade eder.
- Bire-çok: Tek bir varlığın başka bir türden birden fazla varlıkla ilişkili olabileceği bir ilişkiyi temsil eder.
- Çoktan çoka: Bir türdeki birden fazla öğenin başka bir türdeki birden fazla öğeyle ilişkili olabileceği bir ilişkiyi ifade eder. Bu genellikle bir birleşim tablosu gerektirir.
- Yerleştirilmiş nesneler kullanılarak oluşturulan iç içe ilişkiler: Bir varlığın başka bir varlığı özellik olarak içerdiği ve bu iç içe yerleştirilmiş varlığın başka varlıklar da içerebileceği bir ilişkiyi ifade eder. Bu,
@Embeddedek açıklamasını kullanır.
İki yaklaşım arasından seçim yapın
Room'da, öğeler arasındaki ilişkiyi tanımlamanın ve sorgulamanın iki yolu vardır. Şunlardan birini kullanabilirsiniz:
- Yerleştirilmiş nesneler içeren bir ara veri sınıfı veya
- Çoklu harita dönüş türüne sahip bir ilişkisel sorgu işlevi.
Ara veri sınıflarını kullanmak için belirli bir nedeniniz yoksa çoklu harita dönüş türü yaklaşımını kullanmanızı öneririz. Bu yaklaşım hakkında daha fazla bilgi edinmek için Çoklu harita döndürme başlıklı makaleyi inceleyin.
Ara veri sınıfı yaklaşımı, karmaşık SQL sorguları yazmaktan kaçınmanızı sağlar ancak ek veri sınıfları gerektirdiğinden kod karmaşıklığının artmasına da neden olabilir. Kısacası, çoklu harita dönüş türü yaklaşımı, SQL sorgularınızın daha fazla iş yapmasını gerektirir. Ara veri sınıfı yaklaşımı ise kodunuzun daha fazla iş yapmasını gerektirir.
Ara veri sınıfı yaklaşımını kullanma
Ara veri sınıfı yaklaşımında, Room varlıklarınız arasındaki ilişkiyi modelleyen bir veri sınıfı tanımlarsınız. Bu veri sınıfı, bir öğenin örnekleri ile başka bir öğenin örnekleri arasındaki eşleşmeleri yerleştirilmiş nesneler olarak tutar. Sorgu işlevleriniz daha sonra bu veri sınıfının örneklerini uygulamanızda kullanılmak üzere döndürebilir.
Örneğin, belirli kitapları ödünç almış kütüphane kullanıcılarını temsil etmek için bir UserBook veri sınıfı tanımlayabilir ve veritabanından UserBook örneklerinin listesini almak için bir sorgu işlevi tanımlayabilirsiniz:
@Dao interface UserBookDao { @Query( """ SELECT user.name AS userName, book.name AS bookName FROM user JOIN book ON user.id = book.user_id """ ) fun loadUserAndBookNames(): LiveData<List<UserBook>> } data class UserBook(val userName: String, val bookName: String)
Çok haritalı dönüş türü yaklaşımını kullanma
Çoklu harita dönüş türü yaklaşımında, ek veri sınıfları tanımlamanız gerekmez. Bunun yerine, istediğiniz harita yapısına göre işleviniz için multimap dönüş türü tanımlar ve varlıklarınız arasındaki ilişkiyi doğrudan SQL sorgunuzda tanımlarsınız.
Örneğin, aşağıdaki sorgu işlevi, belirli kitapları ödünç almış kütüphane kullanıcılarını temsil etmek için User ve Book örneklerinin eşlemesini döndürür:
@Query( """ SELECT * FROM user JOIN book ON user.id = book.user_id """ ) suspend fun loadUserAndBookNames(): Map<User, List<Book>>
Çok haritalı dönüş türleriyle, başka bir öğenin dahil olmadığı bire bir ilişkileri de sorgulayabilirsiniz. Aşağıdaki sorgu işlevi, User ve @MapColumn ek açıklaması kullanılarak ödünç alınan kitap sayısının eşlemesini döndürür:
@Query( """ SELECT user.*, COUNT(book.id) AS book_count FROM user LEFT JOIN book ON user.id = book.user_id GROUP BY user.id """ ) suspend fun loadUserAndBookCount(): Map<User, @MapColumn(columnName = "book_count") Int>
Yerleşik nesneler oluşturma
Bazen, bir nesne birden fazla özellik içerse bile veritabanı mantığınızda bir varlığı veya veri nesnesini tutarlı bir bütün olarak ifade etmek isteyebilirsiniz. Bu gibi durumlarda, bir nesneyi tablodaki alt özelliklerine ayırmak için @Embedded ek açıklamasını kullanın. Daha sonra, diğer sütunlarda yaptığınız gibi yerleştirilmiş mülkleri sorgulayabilirsiniz.
Örneğin, User sınıfınız street, city, state ve postCode özelliklerinin bir bileşimini temsil eden bir Address özelliği içerebilir. Oluşturulan sütunları tabloda ayrı ayrı depolamak için User sınıfındaki Address özelliğini @Embedded ile açıklama ekleyin. Aşağıdaki kod snippet'inde bu kurulum gösterilmektedir:
data class Address( val street: String?, val state: String?, val city: String?, @ColumnInfo(name = "post_code") val postCode: Int ) @Entity data class User( @PrimaryKey val id: Int, val firstName: String, @Embedded val address: Address? )
User nesnesini temsil eden tabloda şu adlara sahip sütunlar bulunur: id, firstName, street, state, city ve post_code.
Bir öğede aynı türden birden fazla yerleştirilmiş özellik varsa prefix özelliğini ayarlayarak her sütunu benzersiz tutabilirsiniz. Room daha sonra sağlanan değeri, yerleştirilmiş nesnedeki her sütun adının başına ekler.