java - 使用 SQLite 处理 POJO 的 DAO 创建的更好模式

标签 java android sqlite design-patterns ormlite

我正在开发一个 Android 应用程序,该应用程序使用 SQLCipherAndroid 版 ORMLite 来处理 POJO 存储,SQLite 和 Jackson 用于解析.

我想知道是否有比我正在使用的模式(由 stayforit 推荐)更好的模式来获取对应于给定实体类的 DAO。我有超过 30 个实体类,并且随着时间的推移我不断添加一些,每次我都必须创建一个看起来与前一个完全相同的 DAO 类。我如何使用泛型类进行泛化?

这是我的 DbManager 类:

public class DbManager {
    private static DbManager instance;
    private CipherDbHelper dbHelper;
    private SecureSharedPreferences settings;

    private DbManager() {

    }

    private DbManager(Context context, String password) {
        SQLiteDatabase.loadLibs(context);
        dbHelper = new CipherDbHelper(context, password);
    }

    public static void init(Context context, String password) {
        instance = new DbManager(context, password);
    }

    public static DbManager getInstance() {
        if (instance == null) {
            Log.e("DbManager", "DbManager is null");
        }
        return instance;
    }

    public <D extends Dao<T, String>, T> D getDAO(Class<T> clz) throws SQLException {
        return dbHelper.getDao(clz);
    }
}

这是我每次将 POJO 实体添加到我的项目时需要生成的循环 DAO 类的示例:

public class CategoriesDAO extends BaseDAO<EntityCategories> {
    private static CategoriesDAO instance;

    private CategoriesDAO() {
    }

    public synchronized static CategoriesDAO getInstance() {
        if (instance == null) {
            instance = new CategoriesDAO();
        }
        return instance;
    }

    @Override
    public Dao<EntityCategories, String> getDAO() throws SQLException, java.sql.SQLException {
        return DbManager.getInstance().getDAO(EntityCategories.class);
    }
}

这是我在 Activity 中使用它的方式:

CategoriesDAO.getInstance().addOrUpdate(categories);

最佳答案

这就是我喜欢使用 Ormlite DAO 的方式:

CRUD运算符(operator):

public interface CRUDOperator<T> {

    void create(T obj);

    void update(T obj);

    void delete(T obj);
}

repo :

public interface Repo<T> extends CRUDOperator<T>{

    Optional<T> queryForId(Integer id);
    ObservableList<T> queryForAll();
    ...
}

OrmliteRepo:

public class OrmliteRepo<T> implements Repo<T> {

    protected Dao<T, Integer>          dao;

    protected OrmliteRepo(Dao<T, Integer> dao) {
        this.dao = dao;
    }

    public ObservableList<T> queryForAll() throws SQLException {
        List<T> results =  dao.queryForAll();
        return Validators.isNullOrEmpty(results) ? FXCollections.observableArrayList() : FXCollections.observableArrayList(results);
    }

    public Optional<T> queryForId(Integer id) throws SQLException {
        T result = dao.queryForId(id);
        return Optional.ofNullable(result);
    }

    @Override
    public void create(T obj) throws SQLException {
            dao.create(obj);
    }

    @Override
    public void update(T obj) throws SQLException {
            dao.update(obj);
    }

    @Override
    public void delete(T obj) throws SQLException {
            dao.delete(obj);
    }
}

你的 repo :

public class YourRepo extends OrmliteRepo<YourModel> {

    public YourRepo(Dao<YourModel, Integer> dao) {
        super(dao);
    }
}

repo 服务:

public interface RepoService {
    <T> Repo<T> get(Class<T> dataClass);
}

基础 repo 服务:

public class BaseRepoService implements RepoService {

    private RepoFactory            repoFactory;
    private Map<Class<?>, Repo<?>> repoCache;

    public BaseRepoService(RepoFactory repoFactory) {
        this.repoFactory = repoFactory;
        repoCache = new HashMap<>();
    }

    @Override
    public <T> Repo<T> get(Class<T> dataClass) {
        @SuppressWarnings("unchecked")
        Repo<T> repo =  (Repo<T>) repoCache.get(dataClass);

        if (repo == null) {
            repo = createRepo(dataClass);
            repoCache.put(dataClass, repo);
        }
        return repo;
    }

    private <T> Repo<T> createRepo(Class<T> dataClass) {
        return repoFactory.createRepo(dataClass);
    }
}

repo 工厂:

public interface RepoFactory {
    public <T> Repo<T> createRepo(Class<T> dataClass);
}

OrmliteRepoFactory:

public class OrmliteRepoFactory implements RepoFactory {

    private DbAccess                                      dbAccess;
    private final Map<Class<?>, Supplier<OrmliteRepo<?>>> suppliers;

    public OrmliteRepoFactory(DbAccess dbAccess) {
        this.dbAccess = dbAccess;

        suppliers = new HashMap<>();
        suppliers.put(YourModel.class, () -> new YourRepo(getDao(YourModel.class)));
    }

    private <T> Dao<T, Integer> getDao(Class<T> modelClass) {
        return dbAccess.getDaoImplementation(modelClass);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> OrmliteRepo<T> createRepo(Class<T> dataClass) {
        return (OrmliteRepo<T>) suppliers.get(dataClass).get();
    }
}

数据库访问:

public interface DbAccess {
     <T, R> R getDaoImplemantation(Class<T> dataClass);
}

OrmliteDbAccess:

public class OrmliteDbAccess implements DbAccess{

@Override
public <T, R> R getDaoImplementation(Class<T> objectClass) {
    R dao = null;

    try {
        dao = DaoManager.createDao(connectionSource, objectClass);

    } catch (SQLException e) {
        LOGGER.error("Error getting dao for class {}; {}", objectClass, e);
    }
    return dao;
}

现在您需要做的就是将您的存储库的供应商添加到 repoFactory 并使 YourRepo.class 扩展 OrmliteRepo.class。如果我需要特定 repo 的一些额外行为,我将其放入该 repo 实现中。

当你有一个 RepoService 的实例时:

RepoService repoService = new BaseRepoService(ormliteRepoFactory);

您可以像这样访问您的存储库:

Repo<YourModel> repo = repoService.get(YourModel.class);

关于java - 使用 SQLite 处理 POJO 的 DAO 创建的更好模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36506936/

相关文章:

java - 数据无法添加到 android 上的 sqlite 数据库

ruby-on-rails - 找不到安装 sqlite3 公钥环时出错

java - 如何使用EdDSA/Ed448签名算法重新生成私钥?

Java插入排序对象的数组列表?

java - 如何删除 android 中 Bottom Sheet 单对话框 fragment 创建的阴影?

android - Flutter - TextFormField 上的键盘

android - 在 Android studio 中创建一个独立的库模块

java - 局部变量可能未初始化

android - 使用导航组件的某些 fragment 的自定义 "navigate up"行为

Android OrmLite 预填充数据库