ormlite для android: помощь в дизайне и многое другое - PullRequest
4 голосов
/ 24 января 2012

Уже несколько месяцев я начинаю разработку приложения для 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

...