Уже несколько месяцев я начинаю разработку приложения для Android. Я работал около двух лет с Spring Framework и Hibernate. Итак, в поисках инструмента ORM для Android я нашел проект ormlite. Мне это показалось очень интересным, и я решил использовать его в своем приложении.
Кажется, все работает нормально, но я бы попросил экспертов дать несколько советов по разработке приложений для Android с использованием ormlite эффективным и (если возможно) элегантным способом!
Давайте начнем с классов домена.
Все доменные классы реализуют поддельный интерфейс DomainObject:
@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;
.....
}
Тогда у меня есть общий интерфейс Дао
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);
}
реализовано:
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);
}
}
Каждый объект домена имеет свой собственный интерфейс Dao, определяющий дополнительные методы (на тот случай, если нужны другие методы, отличные от определенных в GenericDao):
public interface JobDao extends GenericDao<Job>{
Cursor getReceivedJobs();
...
}
и относительная реализация:
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;
}
}
Так что мои вопросы ...
1) Это реализация типа домена / дао или я ввел избыточный и ненужный код?
2) Это хороший способ работы с ormlite?
3) Полезно ли хранить экземпляр каждого дао в классе, расширяющем Application, или лучше хранить экземпляр dao в каждом действии или хранить в другом месте?
Я также пытался обработать транзакцию, но безуспешно. Я получил исключение, которое говорит о том, что таблица заблокирована. Я создал метод внутри GenericDao, возвращающий новый экземпляр TransactionManager:
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());
}
}
Но когда я выполняю код в БД обновления транзакций, я получаю исключение ...
Спасибо за ваш ответ!
Marco