A few months later, I began to develop applications for Android. I worked for about two years with the Spring framework and Hibernate. So, looking for an ORM tool for android, I found an ormlite project. I was very interested, and I decided to use it in my application.
Everything seems to be working fine, but I would ask experts some advice on developing Android applications using ormlite in an efficient and (if possible) elegant style!
Let's start with the domain classes.
All domain classes implement the fake DomainObject interface:
@DatabaseTable(tableName = "job") public final class Job implements DomainObject{ @DatabaseField(generatedId = true, columnName="_id") public Integer id; @DatabaseField(index=true) public Integer remoteDbid; @DatabaseField public Date downloadDate; @DatabaseField public Date assignedDate; ..... }
Then I have a common Dao interface
public interface GenericDao <T extends DomainObject> { T queryForId(Integer id); List<T> queryForAll(); void save(T object); void merge(T object); void delete(T object); }
implemented:
public class GenericDaoORM <T extends DomainObject> extends OrmLiteSqliteOpenHelper implements GenericDao<T>{ private static final String LOG_TAG = GenericDaoORM.class.getSimpleName(); private final static int DATABASE_VERSION = 7; private final Class<T> type; protected Dao<T, Integer> dao = null; protected GenericDaoORM(final Context context, final Class<T> type) { super(context, FileConfig.DB_PATH, null, DATABASE_VERSION); this.type = type; if (dao == null) { try { dao = getDao(type); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Can't get DAO for "+type.getName(), e); } } } } @Override public T queryForId(final Integer id) { try { return dao.queryForId(id); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Can't get element with id "+id, e); } return null; } } @Override public List<T> queryForAll() { try { return dao.queryForAll(); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Can't get "+ type.getName() +" list", e); } return null; } } @Override public void save(final T object) { try { dao.create(object); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Can't save "+ object.getClass().getName(), e); } } } @Override public void merge(final T object) { try { dao.update(object); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Can't update "+ object.getClass().getName(), e); } } } @Override public void delete(final T object) { try { dao.delete(object); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Can't delete "+ object.getClass().getName(), e); } } } @Override public void onCreate(final SQLiteDatabase database, final ConnectionSource connectionSource) { try { TableUtils.createTableIfNotExists(connectionSource, Job.class); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "Cannot create Tables", e); } } } @Override public void onUpgrade(final SQLiteDatabase database, final ConnectionSource connectionSource, final int oldVersion, final int newVersion) { onCreate(database, connectionSource); } }
Each domain object has its own Dao interface that defines additional methods (just in case you need other methods than those defined in GenericDao):
public interface JobDao extends GenericDao<Job>{ Cursor getReceivedJobs(); ... }
and relative implementation:
public final class JobDaoORM extends GenericDaoORM<Job> implements JobDao { private static final String LOG_TAG = JobDaoORM.class.getSimpleName(); public JobDaoORM(final Context context) { super(context, Job.class); } public Cursor getReceivedJobs() { try{ final QueryBuilder<Job, Integer> queryBuilder = dao.queryBuilder(); queryBuilder.orderBy("reportDate", false); queryBuilder.selectColumns(new String[]{"...", "...", ...}); final Where<Job, Integer> where = queryBuilder.where(); where.eq("executed", true); final PreparedQuery<Job> preparedQuery = queryBuilder.prepare(); final AndroidCompiledStatement compiledStatement = (AndroidCompiledStatement)preparedQuery.compile(connectionSource.getReadOnlyConnection(),StatementType.SELECT); return compiledStatement.getCursor(); } catch (SQLException e) { if (LogConfig.ENABLE_ACRA){ ErrorReporter.getInstance().handleException(e); } if (LogConfig.ERROR_LOGS_ENABLED){ Log.e(LOG_TAG, "getReceivedJobs()", e); } } return null; } }
So my questions are ...
1) Are such implementations of the domain / dao function or have I introduced redundant and unnecessary code?
2) Is this a good way to work with ormlite?
3) Is it good practice to save an instance of each tao in a class extending the application, or is it better to save a dao instance for each action or save it in another place?
I also tried to process the transaction, but without success .. I have an exception saying the table is locked. I created a method inside GenericDao that returns a new TransactionManager instance:
public interface GenericDao <T extends DomainObject> { .... TransactionManager getTransactionManager(); } public class GenericDaoORM <T extends DomainObject> extends OrmLiteSqliteOpenHelper implements GenericDao<T>{ ... @Override public TransactionManager getTransactionManager(){ return new TransactionManager(getConnectionSource()); } }
But when I execute the code in the transaction database, I got an exception ...
Thanks for your reply!
Marco