Room: concetti chiave, Entity, DAO e lavoro con i database

Autore: IT Sectr Pubblicato: 2026-05-04 Tempo di lettura: 8 min

Room è una libreria per lavorare con SQLite in Android, parte di Jetpack. Fornisce un livello di astrazione sopra SQLite grezzo, automatizzando la creazione di tabelle, l’esecuzione di query e la conversione dei dati in oggetti Kotlin e Java. Secondo Android Developers, Room compila le query SQL al momento della build, verificando la correttezza della sintassi e le relazioni tra Entity e tabelle.

Punti chiave

  • Room è una libreria ORM di Jetpack per lavorare con SQLite nelle applicazioni Android.
  • Entity è una classe annotata con @Entity, ogni istanza corrisponde a una riga in una tabella.
  • DAO è un oggetto di accesso ai dati con metodi annotati per query SQL.
  • Database è una classe astratta che estende RoomDatabase, collegando Entity e DAO.
  • Migrazione è un meccanismo per modificare in sicurezza lo schema del database senza perdere i dati dell’utente.

Cos’è Room e perché serve

Room è una libreria di persistenza di Android Jetpack che fornisce il mapping oggetto-relazionale per SQLite. Room risolve tre problemi principali di SQLite grezzo: la scrittura di grandi quantità di codice boilerplate per creare tabelle, la mancanza di verifica delle query SQL al momento della compilazione e la conversione manuale di Cursor in oggetti.

La libreria utilizza un processore di annotazioni (kapt o KSP) che genera l’implementazione delle classi astratte RoomDatabase e DAO al momento della build. Ciò garantisce che gli errori di sintassi in SQL e le discrepanze di tipo vengano scoperti prima dell’esecuzione dell’applicazione, anziché in fase di esecuzione dopo la pubblicazione su Google Play.

Secondo Google I/O 2023, Room è utilizzato nel 68% delle applicazioni Android che lavorano con dati locali. È lo standard per l’archiviazione dei dati sul dispositivo, raccomandato da Google per tutti i nuovi progetti — al posto dei obsoleti SQLiteOpenHelper e ContentProvider.

Integrate Room in progetti che richiedono caching locale dei dati dal server, modalità offline o archiviazione di dati utente strutturati con possibilità di eseguire query SQL complesse.

Room fa parte di Android Jetpack ed è ufficialmente raccomandato da Google per tutti i nuovi progetti che lavorano con dati locali. A differenza di Realm o ObjectBox, Room utilizza SQLite nativo, garantendo la compatibilità con qualsiasi strumento di database di terze parti — da DB Browser a DataGrip. Gli sviluppatori possono aprire il file .db dell’applicazione ed eseguire query SQL direttamente, semplificando il debug e l’analisi dei dati durante lo sviluppo.

Entity e annotazioni in Room

Entity è una classe di dati annotata con @Entity che Room trasforma in una tabella del database. Ogni campo della classe diventa una colonna della tabella e ogni istanza diventa una riga. Room utilizza la riflessione per accedere ai campi, quindi l’annotazione @PrimaryKey è richiesta per un identificatore obbligatorio.

Annotazioni principali

L’annotazione @Entity indica a Room che la classe è una tabella. Il parametro tableName imposta il nome della tabella se diverso dal nome della classe. @PrimaryKey definisce la chiave primaria con supporto alla generazione automatica tramite autoGenerate = true.

kotlin
@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    @ColumnInfo(name = "full_name")
    val name: String,
    @Ignore
    val tempData: String?
)

@ColumnInfo specifica il nome della colonna nella tabella se diverso dal nome del campo Kotlin. @Ignore esclude un campo dalla tabella — non verrà salvato nel database. @ForeignKey descrive le chiavi esterne per le relazioni tra tabelle con operazioni a cascata in caso di eliminazione o aggiornamento.

Room supporta oggetti annidati tramite l’annotazione @Embedded. I campi della classe annidata vengono espansi in colonne della tabella padre con un prefisso per evitare conflitti di nomi. Ad esempio, una classe Address con campi city e street incorporata in User creerà le colonne address_city e address_street nella tabella users, eliminando la necessità di tabelle separate per semplici oggetti valore.

Convertitori di tipo

Room supporta solo tipi primitivi e i loro wrapper. Per memorizzare liste, Date o tipi personalizzati, utilizzare @TypeConverter — metodi statici per convertire tra un tipo personalizzato e un primitivo SQLite, ad esempio, tra List e una stringa JSON.

DAO e query SQL

DAO (Data Access Object) è un’interfaccia o classe astratta annotata con @Dao contenente metodi per l’accesso ai dati. Ogni metodo è annotato con un’operazione SQL: @Insert, @Update, @Delete o @Query con una query SQL esplicita.

@Query con verifica al momento della compilazione

L’annotazione @Query accetta una stringa SQL che Room verifica al momento della compilazione per la correttezza della sintassi e la corrispondenza dei nomi delle colonne con i campi Entity. Room supporta query parametrizzate tramite la sintassi :paramName.

kotlin
@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)

    @Query("SELECT * FROM users ORDER BY name ASC")
    fun getAllUsers(): Flow<List<User>>
}

@Insert supporta le strategie OnConflictStrategy per gestire i conflitti durante l’inserimento di record duplicati. Flow come tipo di ritorno fornisce aggiornamenti reattivi dell’interfaccia utente a ogni modifica dei dati nella tabella — l’abbonamento si riavvia automaticamente a ogni INSERT, UPDATE o DELETE.

@Transaction per operazioni complesse

L’annotazione @Transaction garantisce l’esecuzione atomica di più operazioni in un unico blocco transazionale. Room blocca il database durante l’esecuzione, prevenendo condizioni di gara durante l’accesso concorrente da più thread.

Database e migrazioni dello schema

RoomDatabase è una classe astratta che combina Entity e DAO in un unico punto di accesso al database. Viene creata tramite Room.databaseBuilder con la versione dello schema e un elenco di classi Entity. L’istanza del database dovrebbe essere creata come singleton tramite un delegato lazy per evitare connessioni multiple.

Migrazioni

Una migrazione in Room è una classe Migration che descrive uno script SQL per la transizione da una versione vecchia dello schema a una nuova. Se non viene fornita una migrazione quando lo schema cambia, Room lancia IllegalStateException. Ciò protegge dalla perdita accidentale dei dati dell’utente durante l’aggiornamento dell’applicazione.

kotlin
val migration_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
    }
}

val db = Room.databaseBuilder(
    getApplication(),
    AppDatabase::class.java,
    "app_database"
).addMigrations(migration_1_2)
 .build()

Per lo sviluppo, è possibile utilizzare fallbackToDestructiveMigration, che elimina il vecchio database e ne crea uno nuovo in caso di mancata corrispondenza delle versioni. Questa modalità è destinata solo al debug — le versioni di produzione devono includere migrazioni appropriate.

Per testare il database, Room fornisce una classe speciale Room.inMemoryTestBuilder che crea un database in memoria senza salvare su disco. Dopo il completamento di ogni test, il database viene automaticamente distrutto, garantendo il completo isolamento degli scenari di test. In combinazione con la libreria android-arch-core-testing, gli sviluppatori possono gestire il ciclo di vita del database e verificare la correttezza delle migrazioni senza dover pulire manualmente lo stato.

Le prestazioni di Room dipendono direttamente dalla struttura delle query e dagli indici. Per analizzare le query lente, Room fornisce il flag enableQueryCallback, che registra tutte le query SQL con il tempo di esecuzione. Gli sviluppatori possono utilizzare questo log per trovare query che richiedono più di 100 millisecondi e ottimizzarle aggiungendo indici compositi tramite l’annotazione @Index in @Entity o riscrivendo le sottoquery come operazioni JOIN dirette con @Relation.

Room supporta anche la crittografia del database tramite SQLCipher. L’aggiunta della libreria net.zetetic:android-database-sqlcipher e l’utilizzo di SupportFactory al posto di quella standard fornisce una crittografia trasparente di tutti i dati su disco senza modificare le query DAO o la struttura Entity. Ciò è necessario per le applicazioni che gestiscono dati personali degli utenti ed è conforme al GDPR e alla legge federale russa 152-FZ sulla protezione dei dati personali. La password di crittografia può essere memorizzata in Android Keystore per proteggerla dall’estrazione tramite strumenti su dispositivi rooted.

Room con Kotlin Coroutines e Flow

Room supporta nativamente Kotlin Coroutines a partire dalla versione 2.1. I metodi DAO possono essere funzioni suspend che eseguono query in un thread di background senza bloccare il thread principale. Room gestisce automaticamente i dispatcher, utilizzando Dispatchers.IO per le query di lettura e scrittura.

Per query reattive, Room restituisce un Flow — un flusso di dati freddo che emette un nuovo valore a ogni modifica della tabella interessata. ViewModel si abbona al Flow tramite stateIn o collect, fornendo aggiornamenti automatici dell’interfaccia utente senza notificare manualmente l’adattatore.

Room supporta anche Paging 3 tramite un’implementazione speciale di PagingSource che carica i dati pagina per pagina da SQLite. Ciò è efficiente per grandi elenchi con migliaia di record: Paging 3 carica solo le righe visibili sullo schermo e le aggiorna automaticamente alle modifiche del database.

Utilizzare Paging 3 con Room per visualizzare feed di notizie, log di operazioni o elenchi di prodotti con accesso offline e scorrimento infinito.

Domande frequenti

In cosa si differenzia Room da SQLiteOpenHelper?

Room automatizza la creazione di tabelle, la conversione Cursor-oggetti e la verifica SQL al momento della compilazione. SQLiteOpenHelper richiede di scrivere lo schema manualmente, gestire Cursor e non ha verifica delle query prima dell’esecuzione dell’applicazione, aumentando il rischio di errori.

Devo scrivere migrazioni per ogni modifica dello schema?

Sì, quando si modifica un Entity (aggiunta/rimozione di un campo, modifica di un tipo), è necessaria una migrazione. Senza di essa, Room lancia IllegalStateException all’avvio. Per lo sviluppo, è possibile abilitare fallbackToDestructiveMigration, ma le versioni di produzione richiedono script di migrazione corretti.

Room supporta le relazioni tra tabelle?

Room supporta @ForeignKey per operazioni a cascata e @Relation per oggetti annidati. Per query JOIN complesse, utilizzare l’annotazione @Transaction con @Query che restituisce un POJO con entità annidate tramite @Embedded e @Relation.

Posso usare Room con Java senza Kotlin?

Sì, Room è completamente compatibile con Java. Invece di funzioni suspend, utilizzare LiveData o RxJava Observable; invece di Flow, utilizzare LiveData. Room con Java supporta tutte le stesse annotazioni, ma richiede più codice boilerplate per le operazioni asincrone.

Come funziona la crittografia del database Room?

Room supporta la crittografia tramite SQLCipher di Zetetic. Invece di Room.databaseBuilder, utilizzare SupportFactory dalla libreria net.zetetic:android-database-sqlcipher, passando la password di crittografia. Tutti i dati su disco verranno crittografati in modo trasparente per le query DAO.

Riepilogo

  • Room è una libreria ORM Jetpack per SQLite con verifica SQL al momento della compilazione.
  • @Entity descrive la tabella, @PrimaryKey è l’identificatore, @ColumnInfo è il nome della colonna.
  • @Dao contiene metodi con @Query, @Insert, @Update e @Delete per l’accesso ai dati.
  • RoomDatabase combina Entity e DAO, creato tramite Room.databaseBuilder.
  • Le migrazioni (Migration) descrivono script SQL per modifiche dello schema senza perdita di dati.
  • Room supporta nativamente Kotlin Coroutines (suspend) e Flow per aggiornamenti reattivi dell’interfaccia utente.
  • Per grandi elenchi, utilizzare Paging 3 con Room tramite PagingSource per il caricamento paginato.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche