From 6aa63ff6990b7c38de74deeb7dca4e9664772474 Mon Sep 17 00:00:00 2001 From: laoyuyu Date: Fri, 13 Jan 2023 15:17:42 +0800 Subject: [PATCH] =?UTF-8?q?orm=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PublicComponent/build.gradle | 8 +- PublicComponent/src/main/AndroidManifest.xml | 7 + .../com/arialyy/aria/orm/AbsDelegate.java | 2 +- .../com/arialyy/aria/orm/DbContentProvider.kt | 174 +++ .../main/java/com/arialyy/aria/orm/DbUtil.kt | 83 ++ .../java/com/arialyy/aria/orm/DelegateDel.kt | 54 + .../com/arialyy/aria/orm/DelegateFind.java | 1110 ++++++++--------- .../com/arialyy/aria/orm/DelegateInsert.kt | 56 + .../com/arialyy/aria/orm/DelegateUpdate.java | 193 +-- .../com/arialyy/aria/orm/DelegateWrapper.java | 12 +- build.gradle | 7 +- 11 files changed, 964 insertions(+), 742 deletions(-) create mode 100644 PublicComponent/src/main/java/com/arialyy/aria/orm/DbContentProvider.kt create mode 100644 PublicComponent/src/main/java/com/arialyy/aria/orm/DbUtil.kt create mode 100644 PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateDel.kt create mode 100644 PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateInsert.kt diff --git a/PublicComponent/build.gradle b/PublicComponent/build.gradle index bcf9571f..ebb5075b 100644 --- a/PublicComponent/build.gradle +++ b/PublicComponent/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -33,10 +34,15 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) testImplementation 'junit:junit:4.12' + implementation "androidx.core:core-ktx:+" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } //apply from: 'bintray-release.gradle' ext{ PUBLISH_ARTIFACT_ID = 'public' } -apply from: '../gradle/mavenCentral-release.gradle' \ No newline at end of file +apply from: '../gradle/mavenCentral-release.gradle' +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/PublicComponent/src/main/AndroidManifest.xml b/PublicComponent/src/main/AndroidManifest.xml index 14fe4789..e3231482 100644 --- a/PublicComponent/src/main/AndroidManifest.xml +++ b/PublicComponent/src/main/AndroidManifest.xml @@ -2,4 +2,11 @@ package="com.arialyy.aria.publiccomponent" > + + + + diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/AbsDelegate.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/AbsDelegate.java index 499e81bb..a95fe26e 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/AbsDelegate.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/AbsDelegate.java @@ -21,7 +21,7 @@ import android.database.sqlite.SQLiteDatabase; /** * Created by laoyuyu on 2018/3/22. */ -abstract class AbsDelegate { +public abstract class AbsDelegate { static final String TAG = "AbsDelegate"; void closeCursor(Cursor cursor) { diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DbContentProvider.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/DbContentProvider.kt new file mode 100644 index 00000000..b184e131 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DbContentProvider.kt @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.orm + +import android.content.ContentProvider +import android.content.ContentValues +import android.content.Context +import android.database.Cursor +import android.net.Uri +import com.arialyy.aria.util.ALog +import com.arialyy.aria.util.CommonUtil + +/** + * @Author laoyuyu + * @Description + * @Date 2:25 下午 2022/4/25 + **/ +class DbContentProvider : ContentProvider() { + val TAG = "DbContentProvider" + + companion object { + // const val KEY_TABLE_NAME = "tableName" + const val KEY_ROW_ID = "rowId" + const val KEY_TABLE_CLAZZ = "tableClazz" + const val KEY_LIMIT = "limit" + + fun createRequestUrl(context: Context, clazz: Class<*>): Uri { + return Uri.parse("content://${context.packageName}.com.arialyy.aria.provide/request?${KEY_TABLE_CLAZZ}=${clazz.name}") + } + + fun getRequestUrl(context: Context): String { + return "content://${context.packageName}.com.arialyy.aria.provide/request" + } + + fun getResponseUrl(context: Context): String { + return "content://${context.packageName}.com.arialyy.aria.provide/response" + } + } + + /** + * key: clazzPath, value: tableName + */ + private val tableExistMap = mutableMapOf() + + private lateinit var helper: SqlHelper + + override fun onCreate(): Boolean { + helper = SqlHelper.init(context) + return true + } + + private fun getTableName(uri: Uri): String? { + val db = SqlUtil.checkDb(helper.db) + val clazzName = uri.getQueryParameter(KEY_TABLE_CLAZZ) + if (tableExistMap[clazzName!!] != null) { + return tableExistMap[clazzName] + } + + val clazz: Class? = + javaClass.classLoader?.loadClass(clazzName) as Class? + if (clazz == null) { + ALog.e(TAG, "【$clazz】为空") + return null + } + SqlUtil.checkOrCreateTable(db, clazz) + val tableName = CommonUtil.getClassName(clazz) + tableExistMap[clazzName] = tableName + return tableName + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? { + val db = SqlUtil.checkDb(helper.db) + val tableName = getTableName(uri) + if (tableName.isNullOrBlank()) { + return null + } + val clazzName = uri.getQueryParameter(KEY_TABLE_CLAZZ) + val clazz = javaClass.classLoader?.loadClass(clazzName) as Class? + val columns = SqlUtil.getColumns(clazz) + val limit = uri.getQueryParameter(KEY_LIMIT) + return db.query( + tableName, + columns.toTypedArray(), + selection, + selectionArgs, + null, + null, + null, + limit + ) + } + + override fun getType(uri: Uri): String? { + return null + } + + override fun insert(uri: Uri, values: ContentValues?): Uri? { + val db = SqlUtil.checkDb(helper.db) + val tableName = getTableName(uri) + if (tableName.isNullOrBlank()) { + return null + } + db.beginTransaction() + try { + val rowId = db.insert(tableName, null, values) + if (rowId == -1L) { + return null + } + return Uri.parse("${getResponseUrl(context!!)}?${KEY_ROW_ID}=$rowId") + } finally { + db.endTransaction() + } + } + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { + val db = SqlUtil.checkDb(helper.db) + val tableName = getTableName(uri) + if (tableName.isNullOrBlank()) { + return -1 + } + db.beginTransaction() + try { + val rowId = db.delete(tableName, selection, selectionArgs) + if (rowId == -1) { + return -1 + } + return rowId + } finally { + db.endTransaction() + } + } + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int { + val db = SqlUtil.checkDb(helper.db) + val tableName = getTableName(uri) + if (tableName.isNullOrBlank()) { + return -1 + } + db.beginTransaction() + try { + val rowId = db.update(tableName, values, selection, selectionArgs) + if (rowId == -1) { + return -1 + } + return rowId + } finally { + db.endTransaction() + } + } +} \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DbUtil.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/DbUtil.kt new file mode 100644 index 00000000..ea9fc317 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DbUtil.kt @@ -0,0 +1,83 @@ +package com.arialyy.aria.orm + +import android.content.ContentValues +import android.text.TextUtils +import com.arialyy.aria.orm.annotation.Primary +import com.arialyy.aria.util.CommonUtil +import java.lang.reflect.Field +import java.lang.reflect.Type + +/** + * @Author laoyuyu + * @Description + * @Date 2:58 下午 2022/4/25 + **/ +internal object DbUtil { + /** + * 创建存储数据\更新数据时使用的ContentValues + * + * @return 如果没有字段属性,返回null + */ + fun createValues(dbEntity: DbEntity): ContentValues? { + val fields = CommonUtil.getAllFields(dbEntity.javaClass) + if (fields.size > 0) { + val values = ContentValues() + try { + for (field in fields) { + field.isAccessible = true + if (isIgnore(dbEntity, field)) { + continue + } + var value: String? = null + val type: Type = field.type + if (type === MutableMap::class.java && SqlUtil.checkMap(field)) { + value = SqlUtil.map2Str(field[dbEntity] as Map) + } else if (type === MutableList::class.java && SqlUtil.checkList(field)) { + value = SqlUtil.list2Str(dbEntity, field) + } else { + val obj = field[dbEntity] + if (obj != null) { + value = field[dbEntity].toString() + } + } + values.put(field.name, SqlUtil.encodeStr(value)) + } + return values + } catch (e: IllegalAccessException) { + e.printStackTrace() + } + } + return null + } + + /** + * `true`自动增长的主键和需要忽略的字段 + */ + @Throws(IllegalAccessException::class) private fun isIgnore(obj: Any, field: Field): Boolean { + if (SqlUtil.isIgnore(field)) { + return true + } + // 忽略为空的字段 + val value = field[obj] ?: return true + if (value is String) { + if (TextUtils.isEmpty(value.toString())) { + return true + } + } + if (value is List<*>) { + if (value.size == 0) { + return true + } + } + if (value is Map<*, *>) { + if (value.size == 0) { + return true + } + } + if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键 + val p = field.getAnnotation(Primary::class.java) + return p.autoincrement + } + return false + } +} \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateDel.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateDel.kt new file mode 100644 index 00000000..8615af11 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateDel.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.orm + +import android.content.Context +import com.arialyy.aria.util.ALog +import com.arialyy.aria.util.CommonUtil + +/** + * @Author laoyuyu + * @Description + * @Date 3:55 下午 2022/4/25 + **/ +class DelegateDel : AbsDelegate() { + + /** + * 删除某条数据 + */ + @Synchronized fun delData( + context: Context, + clazz: Class, + vararg expression: String + ) { + if (!CommonUtil.checkSqlExpression(*expression)) { + return + } + val selectionArgs = arrayOfNulls(expression.size - 1) + expression.forEachIndexed { index, s -> + if (index == 0) { + return@forEachIndexed + } + selectionArgs[index - 1] = s + } + + val uri = DbContentProvider.createRequestUrl(context, clazz) + val rowId = context.contentResolver.delete(uri, expression[0], selectionArgs) + if (rowId != -1) { + ALog.d(TAG, "删除成功,删除的rowId = $rowId") + } + } +} \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateFind.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateFind.java index 7d8de8de..9b9a9fac 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateFind.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateFind.java @@ -19,13 +19,11 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.text.TextUtils; import android.util.SparseArray; - import com.arialyy.aria.orm.annotation.Many; import com.arialyy.aria.orm.annotation.One; import com.arialyy.aria.orm.annotation.Wrapper; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; - import java.lang.reflect.Field; import java.net.URLDecoder; import java.net.URLEncoder; @@ -39,603 +37,603 @@ import java.util.Map; * 查询数据 */ class DelegateFind extends AbsDelegate { - private final String PARENT_COLUMN_ALIAS = "p"; - private final String CHILD_COLUMN_ALIAS = "c"; - - private DelegateFind() { - } - - /** - * 获取{@link One}和{@link Many}注解的字段 - * - * @return 返回[OneField, ManyField] ,如果注解依赖错误返回null - */ - private Field[] getOneAndManyField(Class clazz) { - Field[] om = new Field[2]; - Field[] fields = clazz.getDeclaredFields(); - Field one = null, many = null; - boolean hasOne = false, hasMany = false; - for (Field field : fields) { - if (SqlUtil.isOne(field)) { - if (hasOne) { - ALog.w(TAG, "查询数据失败,实体中有多个@One 注解"); - return null; - } - hasOne = true; - one = field; - } - if (SqlUtil.isMany(field)) { - if (hasMany) { - ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解"); - return null; - } - if (!field.getType().isAssignableFrom(List.class)) { - ALog.w(TAG, "查询数据失败,@Many 注解的类型不是List"); - return null; - } - hasMany = true; - many = field; - } + private final String PARENT_COLUMN_ALIAS = "p"; + private final String CHILD_COLUMN_ALIAS = "c"; + + private DelegateFind() { + } + + /** + * 获取{@link One}和{@link Many}注解的字段 + * + * @return 返回[OneField, ManyField] ,如果注解依赖错误返回null + */ + private Field[] getOneAndManyField(Class clazz) { + Field[] om = new Field[2]; + Field[] fields = clazz.getDeclaredFields(); + Field one = null, many = null; + boolean hasOne = false, hasMany = false; + for (Field field : fields) { + if (SqlUtil.isOne(field)) { + if (hasOne) { + ALog.w(TAG, "查询数据失败,实体中有多个@One 注解"); + return null; } - - if (one == null || many == null) { - ALog.w(TAG, "查询数据失败,实体中没有@One或@Many注解"); - return null; + hasOne = true; + one = field; + } + if (SqlUtil.isMany(field)) { + if (hasMany) { + ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解"); + return null; } - - if (many.getType() != List.class) { - ALog.w(TAG, "查询数据失败,@Many注解的字段必须是List"); - return null; + if (!field.getType().isAssignableFrom(List.class)) { + ALog.w(TAG, "查询数据失败,@Many 注解的类型不是List"); + return null; } - om[0] = one; - om[1] = many; - return om; + hasMany = true; + many = field; + } } - /** - * 查找一对多的关联数据 - * 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null - * 如果实体中没有{@link One}或{@link Many}注解,将返回null - * 如果实体中有多个{@link One}或{@link Many}注解,将返回nul - * {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity} - */ - List findRelationData(SQLiteDatabase db, Class clazz, - String... expression) { - return exeRelationSql(db, clazz, 1, Integer.MAX_VALUE, expression); + if (one == null || many == null) { + ALog.w(TAG, "查询数据失败,实体中没有@One或@Many注解"); + return null; } - /** - * 查找一对多的关联数据 - * 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null - * 如果实体中没有{@link One}或{@link Many}注解,将返回null - * 如果实体中有多个{@link One}或{@link Many}注解,将返回nul - * {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity} - */ - List findRelationData(SQLiteDatabase db, Class clazz, - int page, int num, String... expression) { - if (page < 1 || num < 1) { - ALog.w(TAG, "page,num 小于1"); - return null; - } - return exeRelationSql(db, clazz, page, num, expression); + if (many.getType() != List.class) { + ALog.w(TAG, "查询数据失败,@Many注解的字段必须是List"); + return null; } - - /** - * 执行关联查询,如果不需要分页,page和num传-1 - * - * @param page 当前页 - * @param num 一页的数量 - */ - private List exeRelationSql(SQLiteDatabase db, Class wrapperClazz, - int page, int num, String... expression) { - db = checkDb(db); - if (SqlUtil.isWrapper(wrapperClazz)) { - Field[] om = getOneAndManyField(wrapperClazz); - if (om == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - Field one = om[0], many = om[1]; - try { - Many m = many.getAnnotation(Many.class); - Class parentClazz = Class.forName(one.getType().getName()); - Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName()); - // 检查表 - SqlUtil.checkOrCreateTable(db, parentClazz); - SqlUtil.checkOrCreateTable(db, childClazz); - final String pTableName = parentClazz.getSimpleName(); - final String cTableName = childClazz.getSimpleName(); - List pColumn = SqlUtil.getAllNotIgnoreField(parentClazz); - List cColumn = SqlUtil.getAllNotIgnoreField(childClazz); - StringBuilder pSb = new StringBuilder(); - StringBuilder cSb = new StringBuilder(); - - if (pColumn != null) { - pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,")); - for (Field f : pColumn) { - String temp = PARENT_COLUMN_ALIAS.concat(f.getName()); - pSb.append(pTableName.concat(".").concat(f.getName())) - .append(" AS ") - .append(temp) - .append(","); - } - } - - if (cColumn != null) { - pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,")); - for (Field f : cColumn) { - String temp = CHILD_COLUMN_ALIAS.concat(f.getName()); - cSb.append(cTableName.concat(".").concat(f.getName())) - .append(" AS ") - .append(temp) - .append(","); - } - } - - String pColumnAlia = pSb.toString(); - String cColumnAlia = cSb.toString(); - if (!TextUtils.isEmpty(pColumnAlia)) { - pColumnAlia = pColumnAlia.substring(0, pColumnAlia.length() - 1); - } - - if (!TextUtils.isEmpty(cColumnAlia)) { - cColumnAlia = cColumnAlia.substring(0, cColumnAlia.length() - 1); - } - - sb.append("SELECT "); - - if (!TextUtils.isEmpty(pColumnAlia)) { - sb.append(pColumnAlia).append(","); - } - if (!TextUtils.isEmpty(cColumnAlia)) { - sb.append(cColumnAlia); - } - if (TextUtils.isEmpty(pColumnAlia) && TextUtils.isEmpty(cColumnAlia)) { - sb.append(" * "); - } - - sb.append(" FROM ") - .append(pTableName) - .append(" INNER JOIN ") - .append(cTableName) - .append(" ON ") - .append(pTableName.concat(".").concat(m.parentColumn())) - .append(" = ") - .append(cTableName.concat(".").concat(m.entityColumn())); - String sql; - if (expression != null && expression.length > 0) { - if (!CommonUtil.checkSqlExpression(expression)) { - return null; - } - sb.append(" WHERE ").append(expression[0]).append(" "); - sql = sb.toString(); - sql = sql.replace("?", "%s"); - Object[] params = new String[expression.length - 1]; - for (int i = 0, len = params.length; i < len; i++) { - params[i] = String.format("'%s'", SqlUtil.encodeStr(expression[i + 1])); - } - sql = String.format(sql, params); - } else { - sql = sb.toString(); - } - boolean paged = false; - if (page != -1 && num != -1) { - paged = true; - sql = sql.concat(String.format(" Group by %s LIMIT %s,%s", - pTableName.concat(".").concat(m.parentColumn()), (page - 1) * num, num)); - } - Cursor cursor = db.rawQuery(sql, null); - List data = - newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn, - paged, db, m.entityColumn(), m.parentColumn()); - - closeCursor(cursor); - return data; - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } else { - ALog.e(TAG, "查询数据失败,实体类没有使用@Wrapper 注解"); - return null; - } - return null; + om[0] = one; + om[1] = many; + return om; + } + + /** + * 查找一对多的关联数据 + * 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null + * 如果实体中没有{@link One}或{@link Many}注解,将返回null + * 如果实体中有多个{@link One}或{@link Many}注解,将返回nul + * {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity} + */ + List findRelationData(SQLiteDatabase db, Class clazz, + String... expression) { + return exeRelationSql(db, clazz, 1, Integer.MAX_VALUE, expression); + } + + /** + * 查找一对多的关联数据 + * 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null + * 如果实体中没有{@link One}或{@link Many}注解,将返回null + * 如果实体中有多个{@link One}或{@link Many}注解,将返回nul + * {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity} + */ + List findRelationData(SQLiteDatabase db, Class clazz, + int page, int num, String... expression) { + if (page < 1 || num < 1) { + ALog.w(TAG, "page,num 小于1"); + return null; } + return exeRelationSql(db, clazz, page, num, expression); + } + + /** + * 执行关联查询,如果不需要分页,page和num传-1 + * + * @param page 当前页 + * @param num 一页的数量 + */ + private List exeRelationSql(SQLiteDatabase db, Class wrapperClazz, + int page, int num, String... expression) { + db = checkDb(db); + if (SqlUtil.isWrapper(wrapperClazz)) { + Field[] om = getOneAndManyField(wrapperClazz); + if (om == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + Field one = om[0], many = om[1]; + try { + Many m = many.getAnnotation(Many.class); + Class parentClazz = Class.forName(one.getType().getName()); + Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName()); + // 检查表 + SqlUtil.checkOrCreateTable(db, parentClazz); + SqlUtil.checkOrCreateTable(db, childClazz); + final String pTableName = parentClazz.getSimpleName(); + final String cTableName = childClazz.getSimpleName(); + List pColumn = SqlUtil.getAllNotIgnoreField(parentClazz); + List cColumn = SqlUtil.getAllNotIgnoreField(childClazz); + StringBuilder pSb = new StringBuilder(); + StringBuilder cSb = new StringBuilder(); + + if (pColumn != null) { + pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,")); + for (Field f : pColumn) { + String temp = PARENT_COLUMN_ALIAS.concat(f.getName()); + pSb.append(pTableName.concat(".").concat(f.getName())) + .append(" AS ") + .append(temp) + .append(","); + } + } - /** - * 创建关联查询的数据 - * - * @param pColumn 父表的所有字段 - * @param cColumn 字表的所有字段 - */ - private synchronized List newInstanceEntity( - Class wrapperClazz, Class

parentClazz, - Class childClazz, - Cursor cursor, - List pColumn, List cColumn, boolean paged, SQLiteDatabase db, - String entityColumn, String parentColumn) { - List wrappers = new ArrayList<>(); - SparseArray> childs = new SparseArray<>(); // 所有子表数据 - SparseArray parents = new SparseArray<>(); // 所有父表数据 - - try { - while (cursor.moveToNext()) { - int pRowId = cursor.getInt(cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat("rowid"))); - if (childs.get(pRowId) == null) { - childs.put(pRowId, new ArrayList()); - parents.put(pRowId, createParent(pRowId, parentClazz, pColumn, cursor)); - } - if (paged) { - List list = createChildren(db, childClazz, pColumn, entityColumn, parentColumn, - parents.get(pRowId)); - if (list != null) { - childs.get(pRowId).addAll(list); - } - } else { - childs.get(pRowId).add(createChild(childClazz, cColumn, cursor)); - } - } + if (cColumn != null) { + pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,")); + for (Field f : cColumn) { + String temp = CHILD_COLUMN_ALIAS.concat(f.getName()); + cSb.append(cTableName.concat(".").concat(f.getName())) + .append(" AS ") + .append(temp) + .append(","); + } + } - List wFields = SqlUtil.getAllNotIgnoreField(wrapperClazz); - if (wFields == null || wFields.isEmpty()) { - return null; - } - for (int i = 0; i < parents.size(); i++) { - int pRowId = parents.keyAt(i); - T wrapper = wrapperClazz.newInstance(); - boolean isPSet = false, isCSet = false; // 保证One 或 Many 只设置一次 - for (Field f : wFields) { - if (!isPSet && f.getAnnotation(One.class) != null) { - f.set(wrapper, parents.get(pRowId)); - isPSet = true; - } - if (!isCSet && f.getAnnotation(Many.class) != null) { - f.set(wrapper, childs.get(pRowId)); - isCSet = true; - } - } - wrapper.handleConvert(); //处理下转换 - wrappers.add(wrapper); - } - } catch (Exception e) { - e.printStackTrace(); + String pColumnAlia = pSb.toString(); + String cColumnAlia = cSb.toString(); + if (!TextUtils.isEmpty(pColumnAlia)) { + pColumnAlia = pColumnAlia.substring(0, pColumnAlia.length() - 1); } - return wrappers; - } + if (!TextUtils.isEmpty(cColumnAlia)) { + cColumnAlia = cColumnAlia.substring(0, cColumnAlia.length() - 1); + } - /** - * 创建子对象集合 - */ - private List createChildren(SQLiteDatabase db, Class childClazz, - List pColumn, - String entityColumn, String parentColumn, DbEntity parents) - throws IllegalAccessException { + sb.append("SELECT "); - for (Field field : pColumn) { - field.setAccessible(true); - if (field.getName().equals(parentColumn)) { - Object o = field.get(parents); - if (o instanceof String) { - o = URLEncoder.encode((String) o); - } - return findData(db, childClazz, entityColumn + "='" + o + "'"); - } + if (!TextUtils.isEmpty(pColumnAlia)) { + sb.append(pColumnAlia).append(","); } - return new ArrayList(); - } - - /** - * 创建子对象 - */ - private T createChild(Class childClazz, List cColumn, - Cursor cursor) - throws InstantiationException, IllegalAccessException { - T child = childClazz.newInstance(); - child.rowID = cursor.getInt(cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat("rowid"))); - for (Field field : cColumn) { - field.setAccessible(true); - int columnIndex = cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat(field.getName())); - setFieldValue(field.getType(), field, columnIndex, cursor, child); + if (!TextUtils.isEmpty(cColumnAlia)) { + sb.append(cColumnAlia); } - return child; - } - - /** - * 创建父对象 - */ - private T createParent(int rowId, Class parentClazz, List pColumn, - Cursor cursor) - throws InstantiationException, IllegalAccessException { - T parent = parentClazz.newInstance(); - parent.rowID = rowId; - for (Field field : pColumn) { - field.setAccessible(true); - int columnIndex = cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat(field.getName())); - setFieldValue(field.getType(), field, columnIndex, cursor, parent); + if (TextUtils.isEmpty(pColumnAlia) && TextUtils.isEmpty(cColumnAlia)) { + sb.append(" * "); } - return parent; - } - /** - * 条件查寻数据 - */ - List findData(SQLiteDatabase db, Class clazz, String... expression) { - db = checkDb(db); - if (!CommonUtil.checkSqlExpression(expression)) { + sb.append(" FROM ") + .append(pTableName) + .append(" INNER JOIN ") + .append(cTableName) + .append(" ON ") + .append(pTableName.concat(".").concat(m.parentColumn())) + .append(" = ") + .append(cTableName.concat(".").concat(m.entityColumn())); + String sql; + if (expression != null && expression.length > 0) { + if (!CommonUtil.checkSqlExpression(expression)) { return null; + } + sb.append(" WHERE ").append(expression[0]).append(" "); + sql = sb.toString(); + sql = sql.replace("?", "%s"); + Object[] params = new String[expression.length - 1]; + for (int i = 0, len = params.length; i < len; i++) { + params[i] = String.format("'%s'", SqlUtil.encodeStr(expression[i + 1])); + } + sql = String.format(sql, params); + } else { + sql = sb.toString(); } - String sql = String.format("SELECT rowid, * FROM %s WHERE %s", CommonUtil.getClassName(clazz), - expression[0]); - String[] params = new String[expression.length - 1]; - try { - // 处理系统出现的问题:https://github.com/AriaLyy/Aria/issues/450 - System.arraycopy(expression, 1, params, 0, params.length); - } catch (Exception e) { - e.printStackTrace(); - return null; + boolean paged = false; + if (page != -1 && num != -1) { + paged = true; + sql = sql.concat(String.format(" Group by %s LIMIT %s,%s", + pTableName.concat(".").concat(m.parentColumn()), (page - 1) * num, num)); } - - return exeNormalDataSql(db, clazz, sql, params); + Cursor cursor = db.rawQuery(sql, null); + List data = + newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn, + paged, db, m.entityColumn(), m.parentColumn()); + + closeCursor(cursor); + return data; + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } else { + ALog.e(TAG, "查询数据失败,实体类没有使用@Wrapper 注解"); + return null; } - - /** - * 获取分页数据 - */ - List findData(SQLiteDatabase db, Class clazz, int page, int num, - String... expression) { - if (page < 1 || num < 1) { - ALog.w(TAG, "page, bum 小于1"); - return null; - } - db = checkDb(db); - if (!CommonUtil.checkSqlExpression(expression)) { - return null; + return null; + } + + /** + * 创建关联查询的数据 + * + * @param pColumn 父表的所有字段 + * @param cColumn 字表的所有字段 + */ + private synchronized List newInstanceEntity( + Class wrapperClazz, Class

parentClazz, + Class childClazz, + Cursor cursor, + List pColumn, List cColumn, boolean paged, SQLiteDatabase db, + String entityColumn, String parentColumn) { + List wrappers = new ArrayList<>(); + SparseArray> childs = new SparseArray<>(); // 所有子表数据 + SparseArray parents = new SparseArray<>(); // 所有父表数据 + + try { + while (cursor.moveToNext()) { + int pRowId = cursor.getInt(cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat("rowid"))); + if (childs.get(pRowId) == null) { + childs.put(pRowId, new ArrayList()); + parents.put(pRowId, createParent(pRowId, parentClazz, pColumn, cursor)); } - String sql = String.format("SELECT rowid, * FROM %s WHERE %s LIMIT %s,%s", - CommonUtil.getClassName(clazz), - expression[0], (page - 1) * num, num); - - String[] params = new String[expression.length - 1]; - try { - // 处理系统出现的问题:https://github.com/AriaLyy/Aria/issues/450 - System.arraycopy(expression, 1, params, 0, params.length); - } catch (Exception e) { - e.printStackTrace(); - return null; + if (paged) { + List list = createChildren(db, childClazz, pColumn, entityColumn, parentColumn, + parents.get(pRowId)); + if (list != null) { + childs.get(pRowId).addAll(list); + } + } else { + childs.get(pRowId).add(createChild(childClazz, cColumn, cursor)); } + } - return exeNormalDataSql(db, clazz, sql, params); - } - - /** - * 模糊查寻数据 - */ - List findDataByFuzzy(SQLiteDatabase db, Class clazz, - String conditions) { - db = checkDb(db); - if (TextUtils.isEmpty(conditions)) { - throw new IllegalArgumentException("sql语句表达式不能为null或\"\""); - } - if (!conditions.toUpperCase().contains("LIKE")) { - throw new IllegalArgumentException("sql语句表达式未包含LIEK"); + List wFields = SqlUtil.getAllNotIgnoreField(wrapperClazz); + if (wFields == null || wFields.isEmpty()) { + return null; + } + for (int i = 0; i < parents.size(); i++) { + int pRowId = parents.keyAt(i); + T wrapper = wrapperClazz.newInstance(); + boolean isPSet = false, isCSet = false; // 保证One 或 Many 只设置一次 + for (Field f : wFields) { + if (!isPSet && f.getAnnotation(One.class) != null) { + f.set(wrapper, parents.get(pRowId)); + isPSet = true; + } + if (!isCSet && f.getAnnotation(Many.class) != null) { + f.set(wrapper, childs.get(pRowId)); + isCSet = true; + } } - String sql = String.format("SELECT rowid, * FROM %s, WHERE %s", CommonUtil.getClassName(clazz), - conditions); - return exeNormalDataSql(db, clazz, sql, null); + wrapper.handleConvert(); //处理下转换 + wrappers.add(wrapper); + } + } catch (Exception e) { + e.printStackTrace(); } - /** - * 分页、模糊搜索数据 - */ - List findDataByFuzzy(SQLiteDatabase db, Class clazz, - int page, int num, String conditions) { - if (page < 1 || num < 1) { - ALog.w(TAG, "page, bum 小于1"); - return null; - } - db = checkDb(db); - if (TextUtils.isEmpty(conditions)) { - throw new IllegalArgumentException("sql语句表达式不能为null或\"\""); - } - if (!conditions.toUpperCase().contains("LIKE")) { - throw new IllegalArgumentException("sql语句表达式未包含LIEK"); + return wrappers; + } + + /** + * 创建子对象集合 + */ + private List createChildren(SQLiteDatabase db, Class childClazz, + List pColumn, + String entityColumn, String parentColumn, DbEntity parents) + throws IllegalAccessException { + + for (Field field : pColumn) { + field.setAccessible(true); + if (field.getName().equals(parentColumn)) { + Object o = field.get(parents); + if (o instanceof String) { + o = URLEncoder.encode((String) o); } - String sql = String.format("SELECT rowid, * FROM %s WHERE %s LIMIT %s,%s", - CommonUtil.getClassName(clazz), conditions, (page - 1) * num, num); - return exeNormalDataSql(db, clazz, sql, null); + return findData(db, childClazz, entityColumn + "='" + o + "'"); + } } - - /** - * 查找表的所有数据 - */ - List findAllData(SQLiteDatabase db, Class clazz) { - db = checkDb(db); - String sql = String.format("SELECT rowid, * FROM %s", CommonUtil.getClassName(clazz)); - return exeNormalDataSql(db, clazz, sql, null); + return new ArrayList(); + } + + /** + * 创建子对象 + */ + private T createChild(Class childClazz, List cColumn, + Cursor cursor) + throws InstantiationException, IllegalAccessException { + T child = childClazz.newInstance(); + child.rowID = cursor.getInt(cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat("rowid"))); + for (Field field : cColumn) { + field.setAccessible(true); + int columnIndex = cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat(field.getName())); + setFieldValue(field.getType(), field, columnIndex, cursor, child); } - - /** - * 执行查询普通数据的sql语句,并创建对象 - * - * @param sql sql 查询语句 - * @param selectionArgs 查询参数,如何sql语句中查询条件含有'?'则该参数不能为空 - */ - private List exeNormalDataSql(SQLiteDatabase db, Class clazz, - String sql, String[] selectionArgs) { - SqlUtil.checkOrCreateTable(db, clazz); - Cursor cursor; - try { - if (selectionArgs != null) { - String[] temp = new String[selectionArgs.length]; - int i = 0; - for (String arg : selectionArgs) { - temp[i] = SqlUtil.encodeStr(arg); - i++; - } - //sql执行失败 android.database.sqlite.SQLiteException: no such column: filePath 异常 - cursor = db.rawQuery(sql, temp); - } else { - cursor = db.rawQuery(sql, null); - } - List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; - closeCursor(cursor); - return data; - } catch (Exception e) { - e.printStackTrace(); - } - return null; + return child; + } + + /** + * 创建父对象 + */ + private T createParent(int rowId, Class parentClazz, List pColumn, + Cursor cursor) + throws InstantiationException, IllegalAccessException { + T parent = parentClazz.newInstance(); + parent.rowID = rowId; + for (Field field : pColumn) { + field.setAccessible(true); + int columnIndex = cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat(field.getName())); + setFieldValue(field.getType(), field, columnIndex, cursor, parent); } - - /** - * 根据数据游标创建一个具体的对象 - */ - private synchronized List newInstanceEntity(Class clazz, - Cursor cursor) { - List fields = CommonUtil.getAllFields(clazz); - List entitys = new ArrayList<>(); - if (fields != null && fields.size() > 0) { - try { - while (cursor.moveToNext()) { - T entity = clazz.newInstance(); - String primaryName = ""; - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.isIgnore(field)) { - continue; - } - - Class type = field.getType(); - if (SqlUtil.isPrimary(field) && (type == int.class || type == Integer.class)) { - primaryName = field.getName(); - } - - int column = cursor.getColumnIndex(field.getName()); - if (column == -1) continue; - setFieldValue(type, field, column, cursor, entity); - } - //当设置了主键,而且主键的类型为integer时,查询RowID等于主键 - entity.rowID = cursor.getInt( - cursor.getColumnIndex(TextUtils.isEmpty(primaryName) ? "rowid" : primaryName)); - //mDataCache.put(getCacheKey(entity), entity); - entitys.add(entity); - } - closeCursor(cursor); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - return entitys; + return parent; + } + + /** + * 条件查寻数据 + */ + List findData(SQLiteDatabase db, Class clazz, String... expression) { + db = checkDb(db); + if (!CommonUtil.checkSqlExpression(expression)) { + return null; + } + String sql = String.format("SELECT rowid, * FROM %s WHERE %s", CommonUtil.getClassName(clazz), + expression[0]); + String[] params = new String[expression.length - 1]; + try { + // 处理系统出现的问题:https://github.com/AriaLyy/Aria/issues/450 + System.arraycopy(expression, 1, params, 0, params.length); + } catch (Exception e) { + e.printStackTrace(); + return null; } - /** - * 设置字段的值 - * - * @throws IllegalAccessException - */ - private void setFieldValue(Class type, Field field, int columnIndex, Cursor cursor, - DbEntity entity) - throws IllegalAccessException { - if (cursor == null || cursor.isClosed()) { - ALog.e(TAG, "cursor没有初始化"); - return; - } - if (type == String.class) { - String temp = cursor.getString(columnIndex); - if (!TextUtils.isEmpty(temp)) { - field.set(entity, URLDecoder.decode(temp)); - } - } else if (type == int.class || type == Integer.class) { - field.setInt(entity, cursor.getInt(columnIndex)); - } else if (type == float.class || type == Float.class) { - field.setFloat(entity, cursor.getFloat(columnIndex)); - } else if (type == double.class || type == Double.class) { - field.setDouble(entity, cursor.getDouble(columnIndex)); - } else if (type == long.class || type == Long.class) { - field.setLong(entity, cursor.getLong(columnIndex)); - } else if (type == boolean.class || type == Boolean.class) { - String temp = cursor.getString(columnIndex); - if (TextUtils.isEmpty(temp)) { - field.setBoolean(entity, false); - } else { - field.setBoolean(entity, !temp.equalsIgnoreCase("false")); - } - } else if (type == java.util.Date.class || type == java.sql.Date.class) { - field.set(entity, new Date(URLDecoder.decode(cursor.getString(columnIndex)))); - } else if (type == byte[].class) { - field.set(entity, cursor.getBlob(columnIndex)); - } else if (type == Map.class) { - String temp = cursor.getString(columnIndex); - if (!TextUtils.isEmpty(temp)) { - field.set(entity, SqlUtil.str2Map(URLDecoder.decode(temp))); - } - } else if (type == List.class) { - String value = cursor.getString(columnIndex); - if (!TextUtils.isEmpty(value)) { - field.set(entity, SqlUtil.str2List(URLDecoder.decode(value), field)); - } - } + return exeNormalDataSql(db, clazz, sql, params); + } + + /** + * 获取分页数据 + */ + List findData(SQLiteDatabase db, Class clazz, int page, int num, + String... expression) { + if (page < 1 || num < 1) { + ALog.w(TAG, "page, bum 小于1"); + return null; + } + db = checkDb(db); + if (!CommonUtil.checkSqlExpression(expression)) { + return null; + } + String sql = String.format("SELECT rowid, * FROM %s WHERE %s LIMIT %s,%s", + CommonUtil.getClassName(clazz), + expression[0], (page - 1) * num, num); + + String[] params = new String[expression.length - 1]; + try { + // 处理系统出现的问题:https://github.com/AriaLyy/Aria/issues/450 + System.arraycopy(expression, 1, params, 0, params.length); + } catch (Exception e) { + e.printStackTrace(); + return null; } - /** - * 获取所在行Id - */ - int[] getRowId(SQLiteDatabase db, Class clazz) { - db = checkDb(db); - Cursor cursor = db.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null); - int[] ids = new int[cursor.getCount()]; + return exeNormalDataSql(db, clazz, sql, params); + } + + /** + * 模糊查寻数据 + */ + List findDataByFuzzy(SQLiteDatabase db, Class clazz, + String conditions) { + db = checkDb(db); + if (TextUtils.isEmpty(conditions)) { + throw new IllegalArgumentException("sql语句表达式不能为null或\"\""); + } + if (!conditions.toUpperCase().contains("LIKE")) { + throw new IllegalArgumentException("sql语句表达式未包含LIEK"); + } + String sql = String.format("SELECT rowid, * FROM %s, WHERE %s", CommonUtil.getClassName(clazz), + conditions); + return exeNormalDataSql(db, clazz, sql, null); + } + + /** + * 分页、模糊搜索数据 + */ + List findDataByFuzzy(SQLiteDatabase db, Class clazz, + int page, int num, String conditions) { + if (page < 1 || num < 1) { + ALog.w(TAG, "page, bum 小于1"); + return null; + } + db = checkDb(db); + if (TextUtils.isEmpty(conditions)) { + throw new IllegalArgumentException("sql语句表达式不能为null或\"\""); + } + if (!conditions.toUpperCase().contains("LIKE")) { + throw new IllegalArgumentException("sql语句表达式未包含LIEK"); + } + String sql = String.format("SELECT rowid, * FROM %s WHERE %s LIMIT %s,%s", + CommonUtil.getClassName(clazz), conditions, (page - 1) * num, num); + return exeNormalDataSql(db, clazz, sql, null); + } + + /** + * 查找表的所有数据 + */ + List findAllData(SQLiteDatabase db, Class clazz) { + db = checkDb(db); + String sql = String.format("SELECT rowid, * FROM %s", CommonUtil.getClassName(clazz)); + return exeNormalDataSql(db, clazz, sql, null); + } + + /** + * 执行查询普通数据的sql语句,并创建对象 + * + * @param sql sql 查询语句 + * @param selectionArgs 查询参数,如何sql语句中查询条件含有'?'则该参数不能为空 + */ + private List exeNormalDataSql(SQLiteDatabase db, Class clazz, + String sql, String[] selectionArgs) { + SqlUtil.checkOrCreateTable(db, clazz); + Cursor cursor; + try { + if (selectionArgs != null) { + String[] temp = new String[selectionArgs.length]; int i = 0; - while (cursor.moveToNext()) { - ids[i] = cursor.getInt(cursor.getColumnIndex("rowid")); - i++; + for (String arg : selectionArgs) { + temp[i] = SqlUtil.encodeStr(arg); + i++; } - cursor.close(); - return ids; + //sql执行失败 android.database.sqlite.SQLiteException: no such column: filePath 异常 + cursor = db.rawQuery(sql, temp); + } else { + cursor = db.rawQuery(sql, null); + } + List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; + closeCursor(cursor); + return data; + } catch (Exception e) { + e.printStackTrace(); } + return null; + } + + /** + * 根据数据游标创建一个具体的对象 + */ + private synchronized List newInstanceEntity(Class clazz, + Cursor cursor) { + List fields = CommonUtil.getAllFields(clazz); + List entitys = new ArrayList<>(); + if (fields != null && fields.size() > 0) { + try { + while (cursor.moveToNext()) { + T entity = clazz.newInstance(); + String primaryName = ""; + for (Field field : fields) { + field.setAccessible(true); + if (SqlUtil.isIgnore(field)) { + continue; + } - /** - * 获取行Id - */ - int getRowId(SQLiteDatabase db, Class clazz, Object[] wheres, Object[] values) { - db = checkDb(db); - if (wheres.length <= 0 || values.length <= 0) { - ALog.e(TAG, "请输入删除条件"); - return -1; - } else if (wheres.length != values.length) { - ALog.e(TAG, "groupHash 和 vaule 长度不相等"); - return -1; - } - StringBuilder sb = new StringBuilder(); - sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE "); - int i = 0; - for (Object where : wheres) { - sb.append(where).append("=").append("'").append(values[i]).append("'"); - sb.append(i >= wheres.length - 1 ? "" : ","); - i++; + Class type = field.getType(); + if (SqlUtil.isPrimary(field) && (type == int.class || type == Integer.class)) { + primaryName = field.getName(); + } + + int column = cursor.getColumnIndex(field.getName()); + if (column == -1) continue; + setFieldValue(type, field, column, cursor, entity); + } + //当设置了主键,而且主键的类型为integer时,查询RowID等于主键 + entity.rowID = cursor.getInt( + cursor.getColumnIndex(TextUtils.isEmpty(primaryName) ? "rowid" : primaryName)); + //mDataCache.put(getCacheKey(entity), entity); + entitys.add(entity); } - Cursor c = db.rawQuery(sb.toString(), null); - int id = c.getColumnIndex("rowid"); - c.close(); - return id; + closeCursor(cursor); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } - - /** - * 通过rowId判断数据是否存在 - */ - boolean itemExist(SQLiteDatabase db, Class clazz, long rowId) { - return itemExist(db, CommonUtil.getClassName(clazz), rowId); + return entitys; + } + + /** + * 设置字段的值 + * + * @throws IllegalAccessException + */ + private void setFieldValue(Class type, Field field, int columnIndex, Cursor cursor, + DbEntity entity) + throws IllegalAccessException { + if (cursor == null || cursor.isClosed()) { + ALog.e(TAG, "cursor没有初始化"); + return; } - - /** - * 通过rowId判断数据是否存在 - */ - boolean itemExist(SQLiteDatabase db, String tableName, long rowId) { - db = checkDb(db); - String sql = "SELECT rowid FROM " + tableName + " WHERE rowid=" + rowId; - Cursor cursor = db.rawQuery(sql, null); - boolean isExist = cursor.getCount() > 0; - cursor.close(); - return isExist; + if (type == String.class) { + String temp = cursor.getString(columnIndex); + if (!TextUtils.isEmpty(temp)) { + field.set(entity, URLDecoder.decode(temp)); + } + } else if (type == int.class || type == Integer.class) { + field.setInt(entity, cursor.getInt(columnIndex)); + } else if (type == float.class || type == Float.class) { + field.setFloat(entity, cursor.getFloat(columnIndex)); + } else if (type == double.class || type == Double.class) { + field.setDouble(entity, cursor.getDouble(columnIndex)); + } else if (type == long.class || type == Long.class) { + field.setLong(entity, cursor.getLong(columnIndex)); + } else if (type == boolean.class || type == Boolean.class) { + String temp = cursor.getString(columnIndex); + if (TextUtils.isEmpty(temp)) { + field.setBoolean(entity, false); + } else { + field.setBoolean(entity, !temp.equalsIgnoreCase("false")); + } + } else if (type == java.util.Date.class || type == java.sql.Date.class) { + field.set(entity, new Date(URLDecoder.decode(cursor.getString(columnIndex)))); + } else if (type == byte[].class) { + field.set(entity, cursor.getBlob(columnIndex)); + } else if (type == Map.class) { + String temp = cursor.getString(columnIndex); + if (!TextUtils.isEmpty(temp)) { + field.set(entity, SqlUtil.str2Map(URLDecoder.decode(temp))); + } + } else if (type == List.class) { + String value = cursor.getString(columnIndex); + if (!TextUtils.isEmpty(value)) { + field.set(entity, SqlUtil.str2List(URLDecoder.decode(value), field)); + } + } + } + + /** + * 获取所在行Id + */ + int[] getRowId(SQLiteDatabase db, Class clazz) { + db = checkDb(db); + Cursor cursor = db.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null); + int[] ids = new int[cursor.getCount()]; + int i = 0; + while (cursor.moveToNext()) { + ids[i] = cursor.getInt(cursor.getColumnIndex("rowid")); + i++; + } + cursor.close(); + return ids; + } + + /** + * 获取行Id + */ + int getRowId(SQLiteDatabase db, Class clazz, Object[] wheres, Object[] values) { + db = checkDb(db); + if (wheres.length <= 0 || values.length <= 0) { + ALog.e(TAG, "请输入删除条件"); + return -1; + } else if (wheres.length != values.length) { + ALog.e(TAG, "groupHash 和 vaule 长度不相等"); + return -1; + } + StringBuilder sb = new StringBuilder(); + sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE "); + int i = 0; + for (Object where : wheres) { + sb.append(where).append("=").append("'").append(values[i]).append("'"); + sb.append(i >= wheres.length - 1 ? "" : ","); + i++; } + Cursor c = db.rawQuery(sb.toString(), null); + int id = c.getColumnIndex("rowid"); + c.close(); + return id; + } + + /** + * 通过rowId判断数据是否存在 + */ + boolean itemExist(SQLiteDatabase db, Class clazz, long rowId) { + return itemExist(db, CommonUtil.getClassName(clazz), rowId); + } + + /** + * 通过rowId判断数据是否存在 + */ + boolean itemExist(SQLiteDatabase db, String tableName, long rowId) { + db = checkDb(db); + String sql = "SELECT rowid FROM " + tableName + " WHERE rowid=" + rowId; + Cursor cursor = db.rawQuery(sql, null); + boolean isExist = cursor.getCount() > 0; + cursor.close(); + return isExist; + } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateInsert.kt b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateInsert.kt new file mode 100644 index 00000000..f0955027 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateInsert.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.orm + +import android.content.ContentValues +import android.content.Context +import com.arialyy.aria.util.ALog + +/** + * @Author laoyuyu + * @Description + * @Date 2:50 下午 2022/4/25 + **/ +class DelegateInsert : AbsDelegate() { + /** + * 插入多条记录 + */ + @Synchronized fun insertManyData(context: Context, dbEntities: List) { + for (entity in dbEntities) { + insertData(context, entity) + } + } + + /** + * 插入数据 + */ + @Synchronized fun insertData(context: Context, dbEntity: DbEntity) { + val value: ContentValues? = DbUtil.createValues(dbEntity) + if (value == null) { + ALog.e(TAG, "保存记录失败,记录没有属性字段") + } else { + val uri = DbContentProvider.createRequestUrl(context, dbEntity.javaClass) + val responseUri = context.contentResolver.insert(uri, value) + val rowId = responseUri?.getQueryParameter(DbContentProvider.KEY_ROW_ID) + if (rowId.isNullOrBlank()) { + ALog.e(TAG, "插入失败,rowId为空") + } else { + dbEntity.rowID = rowId.toLong() + ALog.d(TAG, "插入完成,responseUrl = $responseUri") + } + } + } +} \ No newline at end of file diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java index ce41af35..742e7f45 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java @@ -16,15 +16,10 @@ package com.arialyy.aria.orm; import android.content.ContentValues; -import android.database.sqlite.SQLiteDatabase; -import android.text.TextUtils; -import com.arialyy.aria.orm.annotation.Primary; +import android.content.Context; +import android.net.Uri; import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; -import java.lang.reflect.Field; -import java.lang.reflect.Type; import java.util.List; -import java.util.Map; /** * Created by laoyuyu on 2018/3/22. 增加数据、更新数据 @@ -33,185 +28,31 @@ class DelegateUpdate extends AbsDelegate { private DelegateUpdate() { } - /** - * 删除某条数据 - */ - synchronized void delData(SQLiteDatabase db, Class clazz, - String... expression) { - SqlUtil.checkOrCreateTable(db, clazz); - db = checkDb(db); - if (!CommonUtil.checkSqlExpression(expression)) { - return; - } - - String sql = "DELETE FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " "; - sql = sql.replace("?", "%s"); - Object[] params = new String[expression.length - 1]; - for (int i = 0, len = params.length; i < len; i++) { - params[i] = String.format("'%s'", SqlUtil.encodeStr(expression[i + 1])); - } - sql = String.format(sql, params); - db.execSQL(sql); - } - /** * 修改某行数据 */ - synchronized void updateData(SQLiteDatabase db, DbEntity dbEntity) { - SqlUtil.checkOrCreateTable(db, dbEntity.getClass()); - db = checkDb(db); - ContentValues values = createValues(dbEntity); + synchronized void updateData(Context context, DbEntity dbEntity) { + Uri uri = DbContentProvider.Companion.createRequestUrl(context, dbEntity.getClass()); + ContentValues values = DbUtil.INSTANCE.createValues(dbEntity); if (values != null) { - db.update(CommonUtil.getClassName(dbEntity), values, "rowid=?", - new String[] { String.valueOf(dbEntity.rowID) }); - } else { - ALog.e(TAG, "更新记录失败,记录没有属性字段"); - } - } - - /** - * 更新多条记录 - */ - synchronized void updateManyData(SQLiteDatabase db, List dbEntities) { - db = checkDb(db); - db.beginTransaction(); - try { - Class oldClazz = null; - String table = null; - for (DbEntity entity : dbEntities) { - if (oldClazz == null || oldClazz != entity.getClass() || table == null) { - oldClazz = entity.getClass(); - table = CommonUtil.getClassName(oldClazz); - } - ContentValues value = createValues(entity); - if (value == null) { - ALog.e(TAG, "更新记录失败,记录没有属性字段"); - } else { - db.update(table, value, "rowid=?", new String[] { String.valueOf(entity.rowID) }); - } - } - db.setTransactionSuccessful(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - db.endTransaction(); - } - } - - /** - * 插入多条记录 - */ - synchronized void insertManyData(SQLiteDatabase db, List dbEntities) { - db = checkDb(db); - db.beginTransaction(); - try { - Class oldClazz = null; - String table = null; - for (DbEntity entity : dbEntities) { - if (oldClazz == null || oldClazz != entity.getClass() || table == null) { - oldClazz = entity.getClass(); - table = CommonUtil.getClassName(oldClazz); - SqlUtil.checkOrCreateTable(db, oldClazz); - } - - ContentValues value = createValues(entity); - if (value == null) { - ALog.e(TAG, "保存记录失败,记录没有属性字段"); - } else { - entity.rowID = db.insert(table, null, value); - } - } - db.setTransactionSuccessful(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - db.endTransaction(); - } - } - - /** - * 插入数据 - */ - synchronized void insertData(SQLiteDatabase db, DbEntity dbEntity) { - SqlUtil.checkOrCreateTable(db, dbEntity.getClass()); - db = checkDb(db); - ContentValues values = createValues(dbEntity); - if (values != null) { - dbEntity.rowID = db.insert(CommonUtil.getClassName(dbEntity), null, values); - } else { - ALog.e(TAG, "保存记录失败,记录没有属性字段"); - } - } - - /** - * 创建存储数据\更新数据时使用的ContentValues - * - * @return 如果没有字段属性,返回null - */ - private ContentValues createValues(DbEntity dbEntity) { - List fields = CommonUtil.getAllFields(dbEntity.getClass()); - if (fields.size() > 0) { - ContentValues values = new ContentValues(); - try { - for (Field field : fields) { - field.setAccessible(true); - if (isIgnore(dbEntity, field)) { - continue; - } - String value = null; - Type type = field.getType(); - if (type == Map.class && SqlUtil.checkMap(field)) { - value = SqlUtil.map2Str((Map) field.get(dbEntity)); - } else if (type == List.class && SqlUtil.checkList(field)) { - value = SqlUtil.list2Str(dbEntity, field); - } else { - Object obj = field.get(dbEntity); - if (obj != null) { - value = field.get(dbEntity).toString(); - } - } - values.put(field.getName(), SqlUtil.encodeStr(value)); - } - return values; - } catch (IllegalAccessException e) { - e.printStackTrace(); + int rowId = context.getContentResolver() + .update(uri, values, "rowid=?", new String[] { String.valueOf(dbEntity.rowID) }); + if (rowId != -1) { + ALog.d(TAG, "更新数据成功,rowid = " + rowId); + } else { + ALog.e(TAG, "更新数据成功,rowid = " + rowId); } + return; } - return null; + ALog.e(TAG, "更新记录失败,记录没有属性字段"); } /** - * {@code true}自动增长的主键和需要忽略的字段 + * 更新多条记录 */ - private boolean isIgnore(Object obj, Field field) throws IllegalAccessException { - if (SqlUtil.isIgnore(field)) { - return true; - } - Object value = field.get(obj); - if (value == null) { // 忽略为空的字段 - return true; - } - if (value instanceof String) { - if (TextUtils.isEmpty(String.valueOf(value))) { - return true; - } - } - if (value instanceof List) { - if (((List) value).size() == 0) { - return true; - } + synchronized void updateManyData(Context context, List dbEntities) { + for (DbEntity entity : dbEntities) { + updateData(context, entity); } - if (value instanceof Map) { - if (((Map) value).size() == 0) { - return true; - } - } - - if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键 - Primary p = field.getAnnotation(Primary.class); - return p.autoincrement(); - } - - return false; } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java index 15ae2eed..037fcc68 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java @@ -29,12 +29,14 @@ public class DelegateWrapper { private SQLiteDatabase mDb; private DelegateManager mDManager; + private Context context; private DelegateWrapper() { } private DelegateWrapper(Context context) { + this.context = context.getApplicationContext(); SqlHelper helper = SqlHelper.init(context.getApplicationContext()); mDb = helper.getDb(); mDManager = DelegateManager.getInstance(); @@ -106,21 +108,21 @@ public class DelegateWrapper { * 删除某条数据 */ void delData(Class clazz, String... expression) { - mDManager.getDelegate(DelegateUpdate.class).delData(mDb, clazz, expression); + mDManager.getDelegate(DelegateDel.class).delData(context, clazz, expression); } /** * 修改某行数据 */ void updateData(DbEntity dbEntity) { - mDManager.getDelegate(DelegateUpdate.class).updateData(mDb, dbEntity); + mDManager.getDelegate(DelegateUpdate.class).updateData(context, dbEntity); } /** * 更新多条数据 */ void updateManyData(List dbEntitys) { - mDManager.getDelegate(DelegateUpdate.class).updateManyData(mDb, dbEntitys); + mDManager.getDelegate(DelegateUpdate.class).updateManyData(context, dbEntitys); } /** @@ -178,14 +180,14 @@ public class DelegateWrapper { * 插入数据 */ void insertData(DbEntity dbEntity) { - mDManager.getDelegate(DelegateUpdate.class).insertData(mDb, dbEntity); + mDManager.getDelegate(DelegateInsert.class).insertData(context, dbEntity); } /** * 插入多条数据 */ void insertManyData(List dbEntitys) { - mDManager.getDelegate(DelegateUpdate.class).insertManyData(mDb, dbEntitys); + mDManager.getDelegate(DelegateInsert.class).insertManyData(context, dbEntitys); } /** diff --git a/build.gradle b/build.gradle index 39e7ddb7..e72e2a9d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { -// ext.kotlin_version = '1.3.20' - ext.kotlin_version = '1.4.30' + ext.kotlin_version = '1.5.20' + // ext.kotlin_version = '1.3.20' repositories { jcenter() mavenCentral() @@ -12,7 +12,8 @@ buildscript { classpath 'com.android.tools.build:gradle:4.1.3' // classpath 'com.novoda:bintray-release:0.9.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}" - classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.4.30" // kotlin 文档引擎 + classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.4.30" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // kotlin 文档引擎 // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' // classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' // NOTE: Do not place your application dependencies here; they belong