使用SQLite处理POJO的DAO创建的更好模式
我正在开发一个使用SQLCipher的Android应用程序, 用于Android的ORMLite处理与SQLite和Jackson进行解析的POJO存储。
我想知道是否会有一个更好的模式,我正在使用(由stayforit推荐)获得对应于给定的实体类的DAO。 我有超过30个实体类,我不断添加一些时间,每次,我必须创建一个看起来与前一个完全相同的DAO类。 我如何使用generics类进行推广?
这是我的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> D getDAO(Class clz) throws SQLException { return dbHelper.getDao(clz); } }
下面是每次向项目添加POJO实体时需要生成的循环DAO类的示例:
public class CategoriesDAO extends BaseDAO { private static CategoriesDAO instance; private CategoriesDAO() { } public synchronized static CategoriesDAO getInstance() { if (instance == null) { instance = new CategoriesDAO(); } return instance; } @Override public Dao getDAO() throws SQLException, java.sql.SQLException { return DbManager.getInstance().getDAO(EntityCategories.class); } }
以下是我在Activity中使用它的方法:
CategoriesDAO.getInstance().addOrUpdate(categories);
您可以将POJO daos的实例存储在BaseDao本身内部或子类中的映射中,然后使用未经检查的强制转换将其解压缩。
public class GenericDao extends BaseDao { private static class InstanceHolder { static final Map, GenericDao>> INSTANCES = new HashMap<>(); } public static synchronized GenericDao getInstance(Class clazz) { GenericDao dao = (GenericDao )InstanceHolder.INSTANCES.get(clazz); if (dao == null) { dao = new GenericDao (); InstanceHolder.INSTANCES.put(clazz, dao); } return dao; } private GenericDao() { } }
接着
GenericDao foo = GenericDao.getInstance(EntityCategories.class); foo.addOrUpdate(....);
这就是我喜欢使用Ormlite DAO的方式:
CRUDOperator:
public interface CRUDOperator { void create(T obj); void update(T obj); void delete(T obj); }
回购:
public interface Repo extends CRUDOperator { Optional queryForId(Integer id); ObservableList queryForAll(); ... }
OrmliteRepo:
public class OrmliteRepo implements Repo { protected Dao dao; protected OrmliteRepo(Dao dao) { this.dao = dao; } public ObservableList queryForAll() throws SQLException { List results = dao.queryForAll(); return Validators.isNullOrEmpty(results) ? FXCollections.observableArrayList() : FXCollections.observableArrayList(results); } public Optional 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); } }
YourRepo:
public class YourRepo extends OrmliteRepo { public YourRepo(Dao dao) { super(dao); } }
RepoService:
public interface RepoService { Repo get(Class dataClass); }
BaseRepoService:
public class BaseRepoService implements RepoService { private RepoFactory repoFactory; private Map, Repo>> repoCache; public BaseRepoService(RepoFactory repoFactory) { this.repoFactory = repoFactory; repoCache = new HashMap<>(); } @Override public Repo get(Class dataClass) { @SuppressWarnings("unchecked") Repo repo = (Repo ) repoCache.get(dataClass); if (repo == null) { repo = createRepo(dataClass); repoCache.put(dataClass, repo); } return repo; } private Repo createRepo(Class dataClass) { return repoFactory.createRepo(dataClass); } }
RepoFactory:
public interface RepoFactory { public Repo createRepo(Class dataClass); }
OrmliteRepoFactory:
public class OrmliteRepoFactory implements RepoFactory { private DbAccess dbAccess; private final Map, Supplier>> suppliers; public OrmliteRepoFactory(DbAccess dbAccess) { this.dbAccess = dbAccess; suppliers = new HashMap<>(); suppliers.put(YourModel.class, () -> new YourRepo(getDao(YourModel.class))); } private Dao getDao(Class modelClass) { return dbAccess.getDaoImplementation(modelClass); } @Override @SuppressWarnings("unchecked") public OrmliteRepo createRepo(Class dataClass) { return (OrmliteRepo ) suppliers.get(dataClass).get(); } }
DBACCESS:
public interface DbAccess { R getDaoImplemantation(Class dataClass); }
OrmliteDbAccess:
public class OrmliteDbAccess implements DbAccess{ @Override public R getDaoImplementation(Class 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。 如果我需要一些特定仓库的额外行为,我会把它放在repo实现中。
当你有一个RepoService的实例时:
RepoService repoService = new BaseRepoService(ormliteRepoFactory);
你可以像这样访问你的回购:
Repo repo = repoService.get(YourModel.class);