package com.litesuits.orm.db.impl; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.litesuits.android.log.Log; import com.litesuits.orm.db.DataBase; import com.litesuits.orm.db.DataBaseConfig; import com.litesuits.orm.db.TableManager; import com.litesuits.orm.db.assit.*; import com.litesuits.orm.db.assit.Transaction.Worker; import com.litesuits.orm.db.model.*; import com.litesuits.orm.db.utils.ClassUtil; import com.litesuits.orm.db.utils.FieldUtil; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; /** * 数据SQLite操作实现 * 可查阅 <a href="http://www.sqlite.org/lang.html">SQLite操作指南</a> * * @author mty * @date 2013-6-2下午2:32:56 */ public class DataBaseSQLiteImpl extends SQLiteClosable implements DataBase { public static final String TAG = DataBaseSQLiteImpl.class.getSimpleName(); private SQLiteHelper mHelper; private DataBaseConfig mConfig; private TableManager mTableManager; protected DataBaseSQLiteImpl(DataBaseConfig config) { if (config.dbName == null) { config.dbName = DataBaseConfig.DEFAULT_DB_NAME; } if (config.dbVersion <= 0) { config.dbVersion = DataBaseConfig.DEFAULT_DB_VERSION; } mConfig = config; mHelper = new SQLiteHelper(mConfig.context.getApplicationContext(), mConfig.dbName, null, mConfig.dbVersion, config.onUpdateListener); mConfig.context = null; mTableManager = new TableManager(mConfig.dbName); } public synchronized static DataBaseSQLiteImpl newInstance(DataBaseConfig config) { return new DataBaseSQLiteImpl(config); } @Override public SQLStatement createSQLStatement(String sql, Object[] bindArgs) { return new SQLStatement(sql, bindArgs); } @Override public boolean execute(SQLiteDatabase db, SQLStatement statement) { acquireReference(); try { if (statement != null) { return statement.execute(db); } } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return false; } @Override public boolean dropTable(Object entity) { acquireReference(); try { return SQLBuilder.buildDropTable(TableManager.getTable(entity)).execute(mHelper.getWritableDatabase()); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return false; } @Override public boolean dropTable(String tableName) { acquireReference(); try { return SQLBuilder.buildDropTable(tableName).execute(mHelper.getWritableDatabase()); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return false; } @Override public DataBase single() { return null; } @Override public DataBase cascade() { return null; } @Override public long save(Object entity) { acquireReference(); try { SQLiteDatabase db = mHelper.getWritableDatabase(); mTableManager.checkOrCreateTable(db, entity); return SQLBuilder.buildReplaceSql(entity).execInsertWithMapping(db, entity, mTableManager); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int save(Collection<?> collection) { acquireReference(); try { if (!Checker.isEmpty(collection)) { SQLiteDatabase db = mHelper.getWritableDatabase(); Object entity = collection.iterator().next(); SQLStatement stmt = SQLBuilder.buildReplaceAllSql(entity); mTableManager.checkOrCreateTable(db, entity); return stmt.execInsertCollection(db, collection, mTableManager); } } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public long insert(Object entity) { return insert(entity, null); } @Override public long insert(Object entity, ConflictAlgorithm conflictAlgorithm) { acquireReference(); try { SQLiteDatabase db = mHelper.getWritableDatabase(); mTableManager.checkOrCreateTable(db, entity); return SQLBuilder.buildInsertSql(entity, conflictAlgorithm).execInsertWithMapping(db, entity, mTableManager); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int insert(Collection<?> collection) { return insert(collection, null); } @Override public int insert(Collection<?> collection, ConflictAlgorithm conflictAlgorithm) { acquireReference(); try { if (!Checker.isEmpty(collection)) { SQLiteDatabase db = mHelper.getWritableDatabase(); Object entity = collection.iterator().next(); SQLStatement stmt = SQLBuilder.buildInsertAllSql(entity, conflictAlgorithm); mTableManager.checkOrCreateTable(db, entity); return stmt.execInsertCollection(db, collection, mTableManager); } } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int update(Object entity) { return update(entity, null, null); } @Override public int update(Object entity, ConflictAlgorithm conflictAlgorithm) { return update(entity, null, conflictAlgorithm); } @Override public int update(Object entity, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { acquireReference(); try { SQLiteDatabase db = mHelper.getWritableDatabase(); return SQLBuilder.buildUpdateSql(entity, cvs, conflictAlgorithm).execUpdateWithMapping(db, entity, mTableManager); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int update(Collection<?> collection) { return update(collection, null, null); } @Override public int update(Collection<?> collection, ConflictAlgorithm conflictAlgorithm) { return update(collection, null, conflictAlgorithm); } @Override public int update(Collection<?> collection, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { acquireReference(); try { if (!Checker.isEmpty(collection)) { SQLiteDatabase db = mHelper.getWritableDatabase(); Object entity = collection.iterator().next(); SQLStatement stmt = SQLBuilder.buildUpdateAllSql(entity, cvs, conflictAlgorithm); return stmt.execUpdateCollection(db, collection, cvs, mTableManager); } } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } /** * 主动删除其mapping数据 */ @Override public int delete(Object entity) { acquireReference(); try { return SQLBuilder.buildDeleteSql(entity).execDeleteWithMapping(mHelper.getWritableDatabase(), entity, mTableManager); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int delete(Class<?> claxx) { return deleteAll(claxx); } @Override public int delete(final Collection<?> collection) { acquireReference(); try { if (!Checker.isEmpty(collection)) { EntityTable table = TableManager.getTable(collection.iterator().next()); if (table.key != null) { SQLStatement stmt = SQLBuilder.buildDeleteSql(collection); return stmt.execDeleteCollection(mHelper.getWritableDatabase(), collection, mTableManager); } else { Integer size = Transaction.execute(mHelper.getWritableDatabase(), new Worker<Integer>() { @Override public Integer doTransaction(SQLiteDatabase db) throws Exception { for (Object entity : collection) { SQLBuilder.buildDeleteSql(entity).execDeleteWithMapping(db, entity, mTableManager); } if (Log.isPrint) { Log.i(TAG, "Exec delete(no primarykey) :" + collection.size()); } return collection.size(); } }); return size == null ? 0 : size; } } } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int delete(Class<?> claxx, WhereBuilder where) { acquireReference(); try { EntityTable table = TableManager.getTable(claxx); if (table.key != null && !Checker.isEmpty(table.mappingList)) { List<?> list = query(QueryBuilder.create(claxx).columns(new String[]{table.key.column}).where(where)); delete(list); } else { return where.createStatementDelete(claxx).execDelete(mHelper.getWritableDatabase()); } } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public int deleteAll(Class<?> claxx) { acquireReference(); try { SQLiteDatabase db = mHelper.getWritableDatabase(); SQLStatement stmt = SQLBuilder.buildDeleteAllSql(claxx); int num = stmt.execDelete(db); // 删除关系映射 final MapInfo mapTable = SQLBuilder.buildDelAllMappingSql(claxx); if (mapTable != null && !mapTable.isEmpty()) { Transaction.execute(db, new Worker<Boolean>() { @Override public Boolean doTransaction(SQLiteDatabase db) throws Exception { if (mapTable.delOldRelationSQL != null) { for (SQLStatement st : mapTable.delOldRelationSQL) { long rowId = st.execDelete(db); if (Log.isPrint) { Log.i(TAG, "Exec delete mapping success, nums: " + rowId); } } } return true; } }); } return num; } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } /** * 删除从[start,end]的数据 * 此方法暂不会删除关联映射表里的关系数据 */ @Override public int delete(Class<?> claxx, long start, long end, String orderAscColumn) { acquireReference(); try { if (start < 0 || end < start) { throw new RuntimeException("start must >=0 and smaller than end"); } if (start != 0) { start -= 1; } end = end == Integer.MAX_VALUE ? -1 : end - start; SQLStatement stmt = SQLBuilder.buildDeleteSql(claxx, start, end, orderAscColumn); return stmt.execDelete(mHelper.getWritableDatabase()); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public long queryCount(Class<?> claxx) { return queryCount(new QueryBuilder(claxx)); } @Override public long queryCount(QueryBuilder qb) { acquireReference(); try { SQLiteDatabase db = mHelper.getReadableDatabase(); SQLStatement stmt = qb.createStatementForCount(); return stmt.queryForLong(db); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return SQLStatement.NONE; } @Override public <T> ArrayList<T> query(QueryBuilder qb) { SQLiteDatabase db = mHelper.getReadableDatabase(); //mTableManager.checkOrCreateTable(db, qb.getQueryClass()); return qb.createStatement().query(db, qb.getQueryClass()); } @Override public <T> T queryById(long id, Class<T> claxx) { return queryById(String.valueOf(id), claxx); } @Override public <T> T queryById(String id, Class<T> claxx) { acquireReference(); try { SQLiteDatabase db = mHelper.getReadableDatabase(); EntityTable table = TableManager.getTable(claxx); SQLStatement stmt = new QueryBuilder(claxx).where(table.key.column + "=?", new String[]{id}).createStatement(); ArrayList<T> list = stmt.query(db, claxx); if (!Checker.isEmpty(list)) { return list.get(0); } } finally { releaseReference(); } return null; } @Override public <T> ArrayList<T> queryAll(Class<T> claxx) { acquireReference(); try { SQLStatement stmt = new QueryBuilder(claxx).createStatement(); return stmt.query(mHelper.getReadableDatabase(), claxx); } finally { releaseReference(); } } @Override public ArrayList<Relation> queryRelation(Class class1, Class class2, List<String> key1List, List<String> key2List) { acquireReference(); try { SQLStatement stmt = SQLBuilder.buildQueryRelationSql(class1, class2, key1List, key2List); final EntityTable table1 = TableManager.getTable(class1); final EntityTable table2 = TableManager.getTable(class2); final ArrayList<Relation> list = new ArrayList<Relation>(); Querier.doQuery(mHelper.getReadableDatabase(), stmt, new Querier.CursorParser() { @Override public void parseEachCursor(SQLiteDatabase db, Cursor c) throws Exception { Relation relation = new Relation(); relation.key1 = c.getString(c.getColumnIndex(table1.name)); relation.key2 = c.getString(c.getColumnIndex(table2.name)); list.add(relation); } }); return list; } finally { releaseReference(); } } @Override public <E, T> boolean mapping(Collection<E> col1, Collection<T> col2) { if (Checker.isEmpty(col1) || Checker.isEmpty(col2)) { return false; } acquireReference(); try { return keepMapping(col1, col2) | keepMapping(col2, col1); } catch (Exception e) { e.printStackTrace(); } finally { releaseReference(); } return false; } @Override public synchronized SQLiteDatabase getReadableDatabase() { return mHelper.getReadableDatabase(); } @Override public synchronized SQLiteDatabase getWritableDatabase() { return mHelper.getWritableDatabase(); } @Override public TableManager getTableManager() { return mTableManager; } @Override public SQLiteHelper getSQLiteHelper() { return mHelper; } @Override public DataBaseConfig getDataBaseConfig() { return mConfig; } @Override public synchronized void close() { releaseReference(); } /** * refCountIsZero 降到0时自动触发释放各种资源 */ @Override protected void onAllReferencesReleased() { mConfig = null; mHelper.close(); mTableManager.clear(); } /* -------------------------------- 私有方法 -------------------------------- */ private <E, T> boolean keepMapping(Collection<E> col1, Collection<T> col2) throws IllegalAccessException, InstantiationException { Class claxx1 = col1.iterator().next().getClass(); Class claxx2 = col2.iterator().next().getClass(); EntityTable table1 = TableManager.getTable(claxx1); EntityTable table2 = TableManager.getTable(claxx2); if (table1.mappingList != null) { for (MapProperty mp : table1.mappingList) { Class itemClass; Class fieldClass = mp.field.getType(); if (mp.isToMany()) { // N对多关系 if (ClassUtil.isCollection(fieldClass)) { itemClass = FieldUtil.getGenericType(mp.field); } else { throw new RuntimeException("OneToMany and ManyToMany Relation, You must use collection object"); } } else { itemClass = fieldClass; } if (itemClass == claxx2) { ArrayList<String> key1List = new ArrayList<String>(); HashMap<String, Object> map1 = new HashMap<String, Object>(); // 构建第1个对象的key集合以及value映射 for (Object o1 : col1) { if (o1 != null) { Object key1 = FieldUtil.get(table1.key.field, o1); if (key1 != null) { key1List.add(key1.toString()); map1.put(key1.toString(), o1); } } } ArrayList<Relation> mapList = queryRelation(claxx1, claxx2, key1List, null); if (!Checker.isEmpty(mapList)) { HashMap<String, Object> map2 = new HashMap<String, Object>(); // 构建第2个对象的value映射 for (Object o2 : col2) { if (o2 != null) { Object key2 = FieldUtil.get(table2.key.field, o2); if (key2 != null) { map2.put(key2.toString(), o2); } } } for (Relation m : mapList) { Object obj1 = map1.get(m.key1); Object obj2 = map2.get(m.key2); if (obj1 != null && obj2 != null) { if (mp.isToMany()) { // N对多关系 if (ClassUtil.isCollection(fieldClass)) { Collection col = (Collection) FieldUtil.get(mp.field, obj1); if (col == null) { col = (Collection) fieldClass.newInstance(); FieldUtil.set(mp.field, obj1, col); } col.add(obj2); } else { throw new RuntimeException("OneToMany and ManyToMany Relation, You must use collection object"); } } else { FieldUtil.set(mp.field, obj1, obj2); } } } return true; } } } } return false; } }