使用 SQLite 处理 POJO 的 DAO 创建的更好模式
Better pattern to handle DAO creation for POJO using SQLite
我正在开发一个 Android 应用程序,它使用 SQLCipher、ORMLite for Android 来处理使用 SQLite 和 Jackson 存储 POJO 进行解析。
我想知道是否有比我正在使用的模式(stayforit 推荐)更好的模式来获取与给定实体 class 对应的 DAO。我有超过 30 个实体 class,而且我不断添加一些,每次,我都必须创建一个看起来与前一个完全相同的 DAO class。我如何使用通用的 class?
进行概括
这是我的 DbManager class:
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);
}
}
这是一个循环 DAO 的例子class我每次向我的项目添加一个 POJO 实体时都需要生成:
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);
您可以将 POJO daos 的实例存储在 BaseDao 本身或子类中的映射中,然后使用未经检查的转换将其提取出来。
public class GenericDao<T> extends BaseDao<T> {
private static class InstanceHolder {
static final Map<Class<?>, GenericDao<?>> INSTANCES = new HashMap<>();
}
public static synchronized <T> GenericDao<T> getInstance(Class<T> clazz) {
GenericDao<T> dao = (GenericDao<T>)InstanceHolder.INSTANCES.get(clazz);
if (dao == null) {
dao = new GenericDao<T>();
InstanceHolder.INSTANCES.put(clazz, dao);
}
return dao;
}
private GenericDao() {
}
}
然后
GenericDao<EntityCategories> foo = GenericDao.getInstance(EntityCategories.class);
foo.addOrUpdate(....);
这就是我喜欢使用 Ormlite DAO 的方式:
CRUD操作员:
public interface CRUDOperator<T> {
void create(T obj);
void update(T obj);
void delete(T obj);
}
回购:
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);
}
}
你的回购:
public class YourRepo extends OrmliteRepo<YourModel> {
public YourRepo(Dao<YourModel, Integer> dao) {
super(dao);
}
}
回购服务:
public interface RepoService {
<T> Repo<T> get(Class<T> dataClass);
}
基础回购服务:
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);
}
}
回购工厂:
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;
}
}
现在您需要做的就是将您的 repos 的供应商添加到 repoFactory 并使 YourRepo.class 扩展 OrmliteRepo.class。如果我需要特定回购的一些额外行为,我将其放入该回购实现中。
当您拥有 RepoService 实例时:
RepoService repoService = new BaseRepoService(ormliteRepoFactory);
您可以像这样访问您的存储库:
Repo<YourModel> repo = repoService.get(YourModel.class);
我正在开发一个 Android 应用程序,它使用 SQLCipher、ORMLite for Android 来处理使用 SQLite 和 Jackson 存储 POJO 进行解析。
我想知道是否有比我正在使用的模式(stayforit 推荐)更好的模式来获取与给定实体 class 对应的 DAO。我有超过 30 个实体 class,而且我不断添加一些,每次,我都必须创建一个看起来与前一个完全相同的 DAO class。我如何使用通用的 class?
进行概括这是我的 DbManager class:
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);
}
}
这是一个循环 DAO 的例子class我每次向我的项目添加一个 POJO 实体时都需要生成:
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);
您可以将 POJO daos 的实例存储在 BaseDao 本身或子类中的映射中,然后使用未经检查的转换将其提取出来。
public class GenericDao<T> extends BaseDao<T> {
private static class InstanceHolder {
static final Map<Class<?>, GenericDao<?>> INSTANCES = new HashMap<>();
}
public static synchronized <T> GenericDao<T> getInstance(Class<T> clazz) {
GenericDao<T> dao = (GenericDao<T>)InstanceHolder.INSTANCES.get(clazz);
if (dao == null) {
dao = new GenericDao<T>();
InstanceHolder.INSTANCES.put(clazz, dao);
}
return dao;
}
private GenericDao() {
}
}
然后
GenericDao<EntityCategories> foo = GenericDao.getInstance(EntityCategories.class);
foo.addOrUpdate(....);
这就是我喜欢使用 Ormlite DAO 的方式:
CRUD操作员:
public interface CRUDOperator<T> {
void create(T obj);
void update(T obj);
void delete(T obj);
}
回购:
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);
}
}
你的回购:
public class YourRepo extends OrmliteRepo<YourModel> {
public YourRepo(Dao<YourModel, Integer> dao) {
super(dao);
}
}
回购服务:
public interface RepoService {
<T> Repo<T> get(Class<T> dataClass);
}
基础回购服务:
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);
}
}
回购工厂:
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;
}
}
现在您需要做的就是将您的 repos 的供应商添加到 repoFactory 并使 YourRepo.class 扩展 OrmliteRepo.class。如果我需要特定回购的一些额外行为,我将其放入该回购实现中。
当您拥有 RepoService 实例时:
RepoService repoService = new BaseRepoService(ormliteRepoFactory);
您可以像这样访问您的存储库:
Repo<YourModel> repo = repoService.get(YourModel.class);