2016-04-08 24 views
1

我工作的一個Android應用程序使用SQLCipherORMLite爲Android處理對POJO存儲與SQLite和傑克遜解析處理DAO創建的POJO。更好的方式使用SQLite

我想知道是否會有一個更好的模式,我正在使用(推薦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); 
    } 
} 

下面是一個經常性的DAO類,我需要每一個我一個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); 
    } 
} 

這裏我如何在活動中使用它:

CategoriesDAO.getInstance().addOrUpdate(categories); 
+0

你可以看看碗櫃作爲替代ORMLite。 https://guides.codepath.com/android/Easier-SQL-with-Cupboard –

+0

@ cricket_007它看起來不錯,但我需要能夠處理特定ORM不支持的嵌套對象(單對多關係) ... – Jaythaking

+0

檢出[JDXA ORM](http://softwaretree.com/v1/products/jdxa/jdxa.html)。 JDXA可以處理嵌套對象,並且不需要爲每個實體(模型)類創建DAO類。 –

回答

1

您可以將POJO daos的實例存儲在地圖eith呃在你的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(....); 
+0

我會試試看,謝謝!沒有檢查會導致一個不好的做法,或者我應該不打擾嗎? – Jaythaking

+0

@總的來說,未審覈的轉換可能是危險的......但在這個特定的用例中,你知道你在這個映射中放入的東西基本上只是一個包含你的類名和關鍵字的關鍵值對......所以你知道你會得到什麼回報。 – Kal

3

這就是我喜歡用Ormlite DAO的方式:

CRUDOperator:

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); 
    } 
} 

YourRepo:

public class YourRepo extends OrmliteRepo<YourModel> { 

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

RepoService:

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

BaseRepoService:

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); 
    } 
} 

RepoFactory:

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(); 
    } 
} 

DBACCESS:

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。如果我需要一些額外的特定回購行爲,我把它放在回購實施中。

當你有RepoService的一個實例:

RepoService repoService = new BaseRepoService(ormliteRepoFactory); 

您可以訪問您的回購協議是這樣的:

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

它看起來很有趣,但對於我最初的目標來說有點矯枉過正,那就是簡化和縮短代碼 – Jaythaking

+0

當我們談到簡單問題時,我並不總是堅信使用複雜模式。但也許你的權利,並允許模塊化的情況下,我想交換到另一個庫比ORMLite ... – Jaythaking

+0

你是絕對正確Jaythaking。對於你的用例來說它是過度的。但關於你的問題的一般性質,我認爲這種模式可能有用。 (我在Gluon多平臺項目上使用它,因此使用這些接口) – jns