➜ Base de Datos Room
Room en Kotlin - CRUD y DAOs | Jetpack Compose App Carta Digital | Implementa Room en tu app con Kotlin y Jetpack Compose. Crea entidades, DAOs, relaciones y CRUD para tu carta digital. Ideal para apps offline.
En este capítulo implementaremos una base de datos local utilizando Room, la librería oficial de persistencia para Android. Con esto podrás almacenar de forma estructurada las categorías, productos y pedidos de tu app, incluso sin conexión a internet.
Configura las dependencias de Room
Abre el archivo build.gradle.kts
(o build.gradle
) y agrega las siguientes dependencias:
// BASE DE DATOS ROOM
implementation(libs.androidx.room.runtime)
kapt(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)
Asegúrate de tener configurado
kapt
en tu proyecto para usar Room con anotaciones.
Luego en libs.versions.toml
[versions]
room = "2.7.1"
[libraries]
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
Crea las entidades
Las entidades representan las tablas de la base de datos. Vamos a crear tres: Category
, Item
y Order
.
🗂️ Category.kt
@Entity(tableName = "categories")
data class Category(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String
)
🍽️ Item.kt
@Entity(
tableName = "items",
foreignKeys = [ForeignKey(
entity = Category::class,
parentColumns = ["id"],
childColumns = ["categoryId"],
onDelete = ForeignKey.CASCADE
)]
)
data class Item(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String,
val description: String?,
val price: Double,
val imageUrl: String?,
val categoryId: Int
)
🧾 Order.kt
@Entity(
tableName = "orders",
foreignKeys = [ForeignKey(
entity = Item::class,
parentColumns = ["id"],
childColumns = ["itemId"],
onDelete = ForeignKey.CASCADE
)]
)
data class Order(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val itemId: Int,
val quantity: Int,
val itemPrice: Double
)
Crea los DAO (Data Access Object)
Los DAO definen las operaciones (CRUD) para cada entidad.
📂 CategoryDao.kt
@Dao
interface CategoryDao {
@Insert
suspend fun insert(category: Category)
@Query("SELECT * FROM categories ORDER BY id ASC")
fun getAllCategories(): Flow<List<Category>>
@Query("SELECT * FROM categories WHERE id = :id")
fun getCategoryById(id: Int): Category?
@Update
suspend fun update(category: Category)
@Delete
suspend fun delete(category: Category)
}
🧾 ItemDao.kt
@Dao
interface ItemDao {
@Insert
suspend fun insert(item: Item)
@Query("SELECT * FROM items ORDER BY id ASC")
fun getAllItems(): Flow<List<Item>>
@Query("SELECT * FROM items WHERE categoryId = :categoryId ORDER BY id ASC")
fun getItemsForCategory(categoryId: Int): Flow<List<Item>>
@Query("SELECT * FROM items WHERE id = :id")
fun getItemsById(id: Int): Item?
@Update
suspend fun update(item: Item)
@Delete
suspend fun delete(item: Item)
}
🛒 OrderDao.kt
@Dao
interface OrderDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(order: Order)
@Update
suspend fun update(order: Order)
@Delete
suspend fun delete(order: Order)
@Query("DELETE FROM orders")
suspend fun clearCart()
@Query("""
SELECT orders.*, items.name AS itemName, items.price AS itemOriginalPrice, items.imageUrl AS itemImageUrl
FROM orders JOIN items ON orders.itemId = items.id
ORDER BY itemName ASC
""")
fun getAllOrdersWithItemDetails(): Flow<List<OrderWithItem>>
data class OrderWithItem(
val id: Int,
val itemId: Int,
val quantity: Int,
val itemPrice: Double,
val itemName: String,
val itemOriginalPrice: Double,
val itemImageUrl: String?
)
}
✅ Nota: Corregimos el JOIN en la consulta para relacionar
orders.itemId
conitems.id
.
Implementa AppDatabase.kt
Esta clase conecta todas las entidades y DAOs:
@Database(
entities = [Category::class, Item::class, Order::class],
version = 1
)
abstract class AppDataBase : RoomDatabase() {
abstract fun CategoryDao(): CategoryDao
abstract fun ItemDao(): ItemDao
abstract fun OrderDao(): OrderDao
companion object {
@Volatile
private var INSTANCE: AppDataBase? = null
fun getDataBase(context: Context): AppDataBase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDataBase::class.java,
"carta_database"
).build()
INSTANCE = instance
instance
}
}
}
}
Conclusión
Con esto ya tienes toda la infraestructura de base de datos lista para funcionar en tu app:
- Tablas con relaciones bien definidas
- DAOs con funciones CRUD
- Base de datos centralizada
519 visitas
Capítulo 5 – ViewModels »
Descarga el código del proyecto
Descarga el código fuente del proyecto adquiriendo el curso completo
Comprar