Un altro modo di rendere persistenti dei dati su piattaforma Android consiste nell'utilizzare SQLite. Android fin
dalle sue prime versioni integra una versione del database SQLite. Come supporto a questo database, l'Android SDK offre,
oltre alle classi che si interfacciano direttamente al suo engine, anche una classe SQLiteOpenHelper
.
Chi ha avuto modo di lavorare con questa classe sa che si tratta di un'operazione che richiede la scrittura di codice ripetitivo che porta via tempo e diventa facilmente fonte di bug.
In questo ambito ci viene incontro con il modulo ORM di Kripton che adotta il pattern DAO secondo il
quale l'accesso ad una base dati avviene definendo:
- Data Access Object Interface: interfaccia dall'oggetto che contiene la logica di
accesso alla base dati. - Data Access Object: implementazione dell'interfaccia precedente.
- Model Object: il Plain Old Java Object (POJO) che rappresenta una tabella.
Ogni suo field è
associato ad una colonna della tabella associata alla classe.
L'insieme dei DAO atti a gestire una base dati viene definita all'interno della dichiarazione di data
source che rappresenta la stessa base dati.
Kripton è in grado, grazie alle sue annotazioni e al suo processore di annotazioni, di generare l'implementazione
del Data Access Object, comprensiva di
javadoc e la classe che rappresenta la base dati o datasource. Ci sono due vincoli da rispettare:
- Ogni classe è associata ad un tabella ed ogni tabella a un classe.
- Ogni classe resa persistente deve avere un attributo di tipo
long
da utilizzare come primary key della
tabella. In SQLite normalmente il nome della PK è
id
. - Ogni DAO può produrre o liste di oggetti della classe ad esso associato o singoli oggetti sempre dello
stesso
tipo o semplici scalari.
Anche in questo caso Kripton supporta buona parte dei tipi inseriti nel JDK, tutti i tipi annotati con @BindTable
o
@BindType
, e tutte le collezioni di oggetti sotto forma di array, liste o set.
Prendiamo ora come esempio la classe Person
vista nel paragrafo sulla persistenza nel file system.
@BindType
public class User {
public long id;
public String name;
public String username;
public String email;
public String phone;
public String website;
}
Per inserirla in un modello di base dati SQLite è necessario dichiarare la relativa DAO interface ed il data source.
Un esempio di interfaccia DAO:
@BindDao(User.class)
public interface UserDao extends BaseDao<User> {
@BindSqlInsert
void insert(User bean);
@BindSqlDelete
void deleteAll();
@BindSqlSelect(orderBy = "username asc")
List<User> selectAll();
@BindSqlSelect(where="id = ${value}")
User selectById(@BindSqlParam("value") long id);
}
Kripton usa delle particolari annotazioni per definire le operazioni di SQL:
@BindSqlSelect
per le operazioni SQL di select.@BindSqlInsert
per le operazioni SQL di insert.@BindSqlUpdate
per le operazioni SQL di update.@BindSqlDelete
per le operazioni SQL di delete.
La definizione del data source avviene grazie ad un'interfaccia annotata con @BindDataSource
. Un esempio di definizione di data source:
@BindDataSource(daoSet={UserDao.class, PostDao.class}, fileName = "sample.db", schema = true, rx=true)
public interface SampleDataSource {
}
A fronte delle classi ed interfacce esposte, Kripton genererà, mediante il suo processore di annotazione in
fase di compilazione, l'implementazione sia del data source
che del DAO. Il nome del DAO sarà in questo caso UserDaoImpl
, mentre per il datasource
sarà BindSampleDataSource
.
Generate queste classi, sarà possibile usare il codice d'esempio riportato di seguito che apre una connessione alla base dati ed
effettua un insert:
try (BindSampleDataSource dataSource = BindSampleDataSource.open()) {
UserDaoImpl userDao = dataSource.getUserDao();
// cancelliamo tutti record già presenti
userDao.deleteAll();
// otteniamo lista user da inserire
userList.forEach(item -> {
userDao.insert(item);
});
}
Il codice SQL può essere anche eseguito in una transazione SQL:
BindSampleDataSource.instance().execute(daoFactory -> {
List<User> users = daoFactory.getUserDao().selectAll();
return TransationResult.COMMIT;
});