手把手带你撸一套Android简易ORM框架
Posted LeBron_Six
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手带你撸一套Android简易ORM框架相关的知识,希望对你有一定的参考价值。
ORM概念
对象关系映射(Object Relational Mapping),通俗来讲就是建立关系型数据库与业务实体对象之间作一个映射关系。对于Java后端来说,例如mybatis、hibernate等,在android平台下,常见的数据库映射框架有 GreenDAO、Realm等。废话不多说,进入正题!
实体模型建立
既然是映射,自然需要对数据库表的字段结构与实体类之间建立一个连接关系。我们采用注解,来通过实体类生成一个表的结构。
注解列
ID
通过 @Id
注解来标识表的ID字段。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Id
主键
通过 @Unique
注解来标识一个主键。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Unique
自增长
通过 @AutoIncrement
注解来标识一个自增长的键。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoIncrement
数据表的列
通过 @Column
注解来标识数据表的一个列,默认不能为null,可通过 nullable 属性修改。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column
boolean nullable() default false;
实体基类
首先,每一个表都有一个唯一的id,所以我们建立的基类里,包含了这个自增长的id。
public abstract class BaseEntity
@Id
@AutoIncrement
private Integer id; // 通过 @Id 与 @AutoIncrement 注解标识为自增长id
public BaseEntity()
public Integer getId()
return id;
public void setId(Integer id) throws DBException
if (id < 1)
throw new DBException(ErrMsg.ERR_INVALID_ID);
this.id = id;
每一个继承实体基类的实体类,都必须生成他的 get
和 set
方法,对于 boolean
来说,为了便于存储与操作,我们在数据库应当把它转换为 1 和 0 的模式。例如:
public class BookConfig extends BaseEntity
@Column
protected String book_num;
@Column
protected String setting_key;
@Column(nullable = true)
protected String setting_value = "";
@Column
protected int status;
@Column(nullable = true)
protected int isModify = 1;
public BookConfig()
public BookConfig(String book_num, String setting_key)
this.book_num = book_num;
this.setting_key = setting_key;
public String getBook_num()
return book_num;
public void setBook_num(String book_num)
this.book_num = book_num;
public String getSetting_key()
return setting_key;
public void setSetting_key(String setting_key)
this.setting_key = setting_key;
public String getSetting_value()
return setting_value;
public void setSetting_value(String setting_value)
this.setting_value = setting_value;
public int getStatus()
return status;
public void setStatus(int status)
this.status = status;
public int getIsModify()
return isModify;
public void setIsModify(int isModify)
this.isModify = isModify;
这样,就创建了一个实体类了。为什么要去生成他的 get
和set
方法呢?这是因为我们需要通过反射来取出每一个字段,然后通过 get
和set
方法去设置字段的值。后面还会提到!
实体类映射成表结构
有个实体类之后,我们就需要把这个实体类转换成一个数据表,通过 @Column
注解去寻找实体类的每一个字段,然后拼接生成对应的SQL语句。
/**
* 生成建表的SQL语句
*
* @param clazz 实体类
* @param strTableName 表名字
* @return
*/
public static String genCreateTableSQL(Class clazz, String strTableName)
boolean isHaveKeyId = false;
boolean isHaveColumnAnnotation = false;
String strIdName = null;
// 反射获取实体类的所有字段
Field[] fields = Utils.getDeclaredField(clazz);
if (fields.length <= 0)
return null;
StringBuilder sb = new StringBuilder("CREATE TABLE IF NOT EXISTS " + strTableName + " ( ");
StringBuilder sbUnique = new StringBuilder("");
for (Field field : fields)
// 添加 自增长id
if (field.isAnnotationPresent(Id.class))
// 一个表只能有一个id
if (isHaveKeyId)
continue;
isHaveColumnAnnotation = true;
Id id = field.getAnnotation(Id.class);
strIdName = getColumnName(field);
sb.append(strIdName);
sb.append(" ");
// type
sb.append(fieldType2DBType(field.getGenericType().toString()));
sb.append(" ");
// primary key
sb.append("NOT NULL PRIMARY KEY ");
// is auto-increment
if (field.isAnnotationPresent(AutoIncrement.class)
&& (field.getGenericType().toString().equals("class java.lang.Integer") || field
.getGenericType().toString().equals("int")))
sb.append("AUTOINCREMENT");
sb.append(",");
isHaveKeyId = true;
else if (field.isAnnotationPresent(Column.class))
// 添加其他列
Column col = field.getAnnotation(Column.class);
String strColName = getColumnName(field);
sb.append(strColName);
sb.append(" ");
// 数据类型
sb.append(fieldType2DBType(field.getGenericType().toString()));
// 是否可以为空
boolean canBeNull = col.nullable();
if (!canBeNull)
sb.append(" NOT NULL");
sb.append(",");
// is unique
if (field.isAnnotationPresent(Unique.class))
sbUnique.append("CONSTRAINT \\"u" + strColName.toLowerCase() + "\\" UNIQUE (\\"" + strColName + "\\"),");
isHaveColumnAnnotation = true;
// nothing
if (!isHaveColumnAnnotation && !isHaveKeyId)
return null;
// unique
sb.append("CONSTRAINT \\"u" + strIdName.toLowerCase() + "\\" UNIQUE (\\"" + strIdName + "\\")");
if (sbUnique.length() > 0)
sb.append(",");
sb.append(sbUnique.deleteCharAt(sbUnique.length() - 1));
// end
sb.append(" )");
return sb.toString();
/**
* Java属性类型转换为数据库数据类型
*
* @param fieldGenericTyp
* @return
*/
private static String fieldType2DBType(String fieldGenericTyp)
if (fieldGenericTyp.equals("class java.lang.String"))
return "VARCHAR";
else if (fieldGenericTyp.equals("class java.lang.Boolean") || fieldGenericTyp.equals("boolean")
|| fieldGenericTyp.equals("class java.lang.Integer") || fieldGenericTyp.equals("int")
|| fieldGenericTyp.equals("class java.lang.Long") || fieldGenericTyp.equals("long")
|| fieldGenericTyp.equals("class java.lang.Short") || fieldGenericTyp.equals("short")
|| fieldGenericTyp.equals("class java.lang.Byte") || fieldGenericTyp.equals("byte"))
return "INTEGER";
else if (fieldGenericTyp.equals("class [B"))
return "BLOB";
else if (fieldGenericTyp.equals("class java.lang.Float") || fieldGenericTyp.equals("float"))
return "float";
else if (fieldGenericTyp.equals("class java.lang.Double") || fieldGenericTyp.equals("double"))
return "double";
return null;
这样的话,我们只要调用以下代码,就可以生成SQL语句。例如:
String sql = ORMUtils.genCreateTableSQL(BookConfig.class, "book_config");
数据库操作封装
表创建完之后,我们就需要封装一些基本数据库操作的方法,也就是增删改查。 首先,建立一个操作方法接口:
public interface IDAO<T extends BaseEntity>
/**
* get the sqlite database object
*
* @return
*/
SQLiteDatabase getDatabase();
/**
* init table name and entityClass
*
* @param tableName
* @param clazz
*/
void initTable(String tableName, Class<T> clazz);
/**
* get count of entities
*
* @return
* @throws DBException
*/
long getCount() throws DBException;
boolean isTableExist(String tableName) throws DBException;
/**
* check table exists
*
* @return
* @throws DBException
*/
boolean isTableExist() throws DBException;
/**
* create table
*
* @throws DBException
*/
void createTable() throws DBException;
/**
* create table
*
* @param tableName table name
* @throws DBException
*/
<T> void createTable(Class<T> entityClass, String tableName) throws DBException;
/**
* drop table
*
* @throws DBException
*/
void dropTable() throws DBException;
/**
* drop all table
*
* @throws DBException
*/
void dropAllTable() throws DBException;
/**
* save database entity
*
* @param entity
* @throws DBException
*/
void save(T entity) throws DBException;
/**
* delete database entity by id(primary key)
*
* @param id
* @throws DBException
*/
void delete(int id) throws DBException;
/**
* delete database entity by ids(primary key)
*
* @param ids
* @throws DBException
*/
void delete(int[] ids) throws DBException;
/**
* delete all data
*
* @throws DBException
*/
void deleteAll() throws DBException;
/**
* update entity
*
* @param entity
* @throws DBException
*/
void update(T entity) throws DBException;
/**
* update entity by a condition string
*
* @param condition part of the update SQL command after keyword 'WHERE'
* (i.e."UPDATE Person SET age = 35 WHERE condition")
* (e.g. condition -- "name = 'Richard' OR name = 'Jefferson'")
* @param entity
* @throws DBException
*/
void updateByCondition(String condition, T entity) throws DBException;
/**
* find entity by id
*
* @param id
* @return
* @throws DBException
*/
T find(int id) throws DBException;
/**
* find last entity
*
* @return
* @throws DBException
*/
T findLastEntity() throws DBException;
/**
* find entities by a condition string
*
* @param condition part of the select SQL command after keyword 'WHERE'
* (i.e."SELECT * FROM Person WHERE condition")
* (e.g. condition -- "name = 'Richard' OR name = 'Jefferson'")
* @return
*/
List<T> findByCondition(String condition) throws DBException;
/**
* find all entities
*
* @return
* @throws DBException
*/
List<T> findAll() throws DBException;
接口主要封装了一些比较常用的增删改查方法,当然了,特别复杂的操作,还是需要配合SQL语句来进行执行,但是这样已经可以满足一些常用的基本操作了。
接着我们需要来具体实现这一系列方法:
public class DAO<T extends BaseEntity> extends SQLiteOpenHelper implements IDAO<T>
private Context mContext;
private String mDBName;
private String mTableName;
private int mVersion;
private SQLiteDatabase db;
private Field[] fields;
private Class<T> entityClass;
public DBUpdateInfo info = new DBUpdateInfo();
/**
* constructor. only for operate the database and cannot operate the specified table.
*
* @param context to use to open or create the database
* @param dbName of the database name, it will be stored in /data/data/%package_name%/files
* @param version number of the database (starting at 1)
*/
public DAO(Context context, String dbName, int version)
this(context, dbName, null, null, version);
/**
* constructor
*
* @param context to use to open or create the database
* @param dbName of the database name, it will be stored in /data/data/%package_name%/files
* @param tableName the name of table to needs to be operated
* @param entityClass class for entity
* @param version number of the database (starting at 1)
*/
public DAO(Context context, String dbName, String tableName, Class<T> entityClass, int version)
super(context, dbName, null, version);
this.mContext = context;
this.mDBName = dbName;
this.mTableName = tableName;
this.mVersion = version;
this.db = getWritableDatabase();
this.fields = Utils.getDeclaredField(entityClass);
this.entityClass = entityClass;
@Override
public void onCreate(SQLiteDatabase db)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
info.isUpdate = true;
info.from = oldVersion;
info.to = newVersion;
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)
info.isUpdate = true;
info.from = oldVersion;
info.to = newVersion;
@Override
public void initTable(String tableName, Class<T> clazz)
this.mTableName = tableName;
this.entityClass = clazz;
this.fields = Utils.getDeclaredField(entityClass);
@Override
public SQLiteDatabase getDatabase()
return db == null ? (db = getWritableDatabase()) : db;
@Override
public long getCount() throws DBException
if (TextUtils.isEmpty(mTableName))
return 0;
try
openDB(true);
String sql = "SELECT COUNT(*) FROM " + mTableName;
LogUtils.d(sql);
Cursor cursor = db.rawQuery(sql, null);
cursor.moveToFirst();
long total = cursor.getLong(0);
return total;
catch (Exception e)
throw new DBException(ErrMsg.ERR_GET_COUNT);
finally
closeDB();
@Override
public boolean isTableExist(String tableName) throws DBException
boolean isExist = false;
if (TextUtils.isEmpty(tableName))
return isExist;
try
openDB(false);
String sql = "SELECT COUNT(*) FROM Sqlite_master WHERE TYPE ='table' AND NAME ='" + tableName.trim() + "' ";
LogUtils.d(sql);
Cursor cursor = db.rawQuery(sql, null);
if (cursor.moveToNext())
int count = cursor.getInt(0);
if (count > 0)
isExist = true;
return isExist;
catch (Exception e)
throw new DBException(ErrMsg.ERR_IS_TABLE_EXISTS);
finally
closeDB();
@Override
public boolean isTableExist() throws DBException
return !TextUtils.isEmpty(mTableName) && isTableExist(mTableName);
@Override
public void createTable() throws DBException
createTable(entityClass, mTableName);
@Override
public <T> void createTable(Class<T> entityClass, String tableName) throws DBException
try
openDB(true);
String sql = ORMUtils.genCreateTableSQL(entityClass, tableName);
LogUtils.i(sql);
db.execSQL(sql);
catch (Exception e)
e.printStackTrace();
throw new DBException(ErrMsg.ERR_CREATE_TABLE, e);
finally
closeDB();
@Override
public void dropTable() throws DBException
try
openDB(true);
String sql = "DROP TABLE " + mTableName;
LogUtils.d(sql);
db.beginTransaction();
db.execSQL(sql);
db.setTransactionSuccessful();
catch (Exception e)
throw new DBException(ErrMsg.ERR_DROP_TABLE, e);
finally
db.endTransaction();
closeDB();
@Override
public void dropAllTable() throws DBException
String strTabSql = "select name from sqlite_master where type='table' order by name";
LogUtils.d("dropAllTable:" + strTabSql);
try
openDB(false);
db.beginTransaction();
Cursor cursor = db.rawQuery(strTabSql, null);
while (cursor.moveToNext())
String name = cursor.getString(0);
if (name.equals("sqlite_sequence"))
continue;
String sql = "DROP TABLE " + name;
LogUtils.d(sql);
db.execSQL(sql);
db.setTransactionSuccessful();
catch (Exception e)
e.printStackTrace();
throw new DBException(ErrMsg.ERR_DROP_TABLE, e);
finally
db.endTransaction();
closeDB();
@Override
public void save(T entity) throws DBException
ContentValues values;
try
openDB(true);
values = Utils.putValue(fields, entity);
if (values == null || values.size() <= 0)
throw new DBException(ErrMsg.ERR_SAVE_PARAM);
long flag = db.insert(mTableName, null, values);
if (flag < 1)
throw new DBException(ErrMsg.ERR_SAVE_PARAM);
catch (Exception e)
throw new DBException(ErrMsg.ERR_SAVE_PARAM, e);
finally
closeDB();
@Override
public void delete(int id) throws DBException
delete(new int[]id);
@Override
public void delete(int[] ids) throws DBException
int length = ids == null ? 0 : ids.length;
if (length <= 0)
throw new DBException(ErrMsg.ERR_DEL_PARAM);
Field pkField = ORMUtils.getPKField(fields);
if (pkField == null)
throw new DBException(ErrMsg.ERR_GET_PRIMARY_KEY);
Class pkType = pkField.getType();
String columnName = ORMUtils.getColumnName(pkField);
try
openDB(true);
StringBuilder sbSql = new StringBuilder("DELETE FROM " + mTableName + " WHERE " + columnName);
if (ids.length == 1)
sbSql.append(" = ");
else
sbSql.append(" in (");
String strSep = "";
if (pkType == String.class)
strSep = "'";
StringBuilder strEntityIds = new StringBuilder("");
for (Serializable id : ids)
strEntityIds.append(strSep);
strEntityIds.append(id);
strEntityIds.append(strSep);
strEntityIds.append(",");
strEntityIds.deleteCharAt(strEntityIds.length() - 1);
sbSql.append(strEntityIds.toString());
if (ids.length > 1)
sbSql.append(")");
LogUtils.d(sbSql.toString());
db.execSQL(sbSql.toString());
catch (Exception e)
throw new DBException(ErrMsg.ERR_DEL, e);
finally
closeDB();
@Override
public void deleteAll() throws DBException
try
openDB(true);
String delSql = "DELETE FROM " + mTableName;
String revSeqSql = "UPDATE SQLITE_SEQUENCE SET SEQ=0 WHERE NAME='" + mTableName + "'";
db.beginTransaction();
db.execSQL(delSql);
db.execSQL(revSeqSql);
db.setTransactionSuccessful();
LogUtils.d(delSql);
LogUtils.d(revSeqSql);
catch (Exception e)
throw new DBException(ErrMsg.ERR_DEL, e);
finally
db.endTransaction();
closeDB();
@Override
public void update(T entity) throws DBException
if (entity == null)
throw new DBException(ErrMsg.ERR_UPDATE_PARAM);
Field pkField = ORMUtils.getPKField(fields);
if (pkField == null)
throw new DBException(ErrMsg.ERR_GET_PRIMARY_KEY);
Object pkValue = Utils.getPropValue(entity, pkField, entityClass);
if (pkValue == null)
throw new DBException(ErrMsg.ERR_GET_PRIMARY_KEY_VALUE);
ContentValues values;
try
openDB(true);
values = Utils.putValue(fields, entity);
if (values.size() <= 0)
throw new DBException(ErrMsg.ERR_UPDATE_PARAM);
int flag = db.update(mTableName, values, pkField.getName() + "=?",
new String[]String.valueOf(pkValue));
if (flag < 1)
throw new DBException(ErrMsg.ERR_UPDATE_PARAM);
catch (Exception e)
throw new DBException(ErrMsg.ERR_UPDATE, e);
finally
closeDB();
@Override
public void updateByCondition(String condition, T entity) throws DBException
if (entity == null)
throw new DBException(ErrMsg.ERR_UPDATE_PARAM);
ContentValues values;
try
openDB(true);
values = Utils.putValue(fields, entity);
values.remove("id");
if (values.size() <= 0)
throw new DBException(ErrMsg.ERR_UPDATE_PARAM);
int flag = db.update(mTableName, values, condition, null);
if (flag < 1)
throw new DBException(ErrMsg.ERR_UPDATE_PARAM);
catch (Exception e)
throw new DBException(ErrMsg.ERR_UPDATE, e);
finally
closeDB();
@Override
public T find(int id) throws DBException
Field pkField = ORMUtils.getPKField(fields);
if (pkField == null)
throw new DBException(ErrMsg.ERR_GET_PRIMARY_KEY);
String columnName = ORMUtils.getColumnName(pkField);
try
openDB(true);
String sql = "SELECT * FROM " + mTableName + " WHERE " + columnName + "=?";
LogUtils.d(sql);
Cursor cursor = db.rawQuery(sql, new String[]id + "");
List<T> objList = Utils.cursor2Entity(entityClass, cursor);
if (objList != null && objList.size() > 0)
return objList.get(0);
catch (Exception e)
throw new DBException(ErrMsg.ERR_FIND, e);
finally
closeDB();
return null;
@Override
public T findLastEntity() throws DBException
Field pkField = ORMUtils.getPKField(fields);
if (pkField == null)
throw new DBException(ErrMsg.ERR_GET_PRIMARY_KEY);
String columnName = ORMUtils.getColumnName(pkField);
try
openDB(true);
String sql = "SELECT * FROM " + mTableName + " ORDER BY " + columnName + " desc LIMIT 1";
LogUtils.d(sql);
Cursor cursor = db.rawQuery(sql, new String[]);
List<T> objList = Utils.cursor2Entity(entityClass, cursor);
if (objList != null && objList.size() > 0)
return objList.get(0);
catch (Exception e)
throw new DBException(ErrMsg.ERR_FIND, e);
finally
closeDB();
return null;
@Override
public List<T> findByCondition(String condition) throws DBException
if (TextUtils.isEmpty(condition))
throw new DBException(null);
try
openDB(true);
String sql = "SELECT * FROM " + mTableName + " WHERE " + condition;
LogUtils.d(sql);
Cursor cursor = db.rawQuery(sql, new String[]);
List<T> objList = Utils.cursor2Entity(entityClass, cursor);
if (objList != null && objList.size() > 0)
return objList;
catch (Exception e)
throw new DBException(null);
finally
closeDB();
return null;
@Override
public List<T> findAll() throws DBException
try
openDB(true);
String sql = "SELECT * FROM " + mTableName;
LogUtils.d(sql);
Cursor cursor = db.rawQuery(sql, new String[]);
List<T> objList = Utils.cursor2Entity(entityClass, cursor);
if (objList != null && objList.size() > 0)
return objList;
catch (Exception e)
throw new DBException(ErrMsg.ERR_FIND, e);
finally
closeDB();
return null;
/**
* Create and/or open a database that will be used for reading and writing.
*
* @param checkTable True if need check mTableName, false otherwise
* @throws DBException
*/
private void openDB(boolean checkTable) throws DBException
if (checkTable && TextUtils.isEmpty(mTableName))
throw new DBException(ErrMsg.ERR_IS_TABLE_EXISTS);
db = getWritableDatabase();
/**
* Releases a reference to the database
* closing the database if the last reference was released.
*/
private void closeDB()
if (db != null && db.isOpen())
db.close();
/**
* database version update information
*/
public class DBUpdateInfo
public boolean isUpdate = false;
public int from;
public int to;
那么,数据库查询出来的行,如何转换为实体呢? 就是通过实体类的 set
方法去赋值。
/**
* 数据库查询->实体对象
*/
public static <T extends BaseEntity> List<T> cursor2Entity(Class<T> clazz, Cursor cursor) throws DBException
List<T> objList = new ArrayList<>();
Field[] fields = getDeclaredField(clazz);
try
if (cursor.moveToFirst())
while (!cursor.isAfterLast())
T obj = clazz.newInstance();
for (int i = 0; i < cursor.getColumnCount(); i++)
String strColName = cursor.getColumnName(i);
for (Field field : fields)
if (field.getName().equals(strColName))
strColName = toUpperCaseFirstOne(strColName);
if (cursor.getType(i) == Cursor.FIELD_TYPE_NULL)
continue;
else if (cursor.getType(i) == Cursor.FIELD_TYPE_FLOAT)
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
cursor.getFloat(i));
else if (cursor.getType(i) == Cursor.FIELD_TYPE_INTEGER)
if (field.getGenericType().toString().equals("class java.lang.Boolean")
|| field.getGenericType().toString().equals("boolean"))
// e.g. boolean isOk; public boolean isOk() return isOk; public void setOk()
clazz.getMethod("set" + strColName.replaceFirst("Is", ""), field.getType()).invoke(obj,
cursor.getInt(i) == 1 ? true : false);
else if (field.getGenericType().toString().equals("class java.lang.Integer")
|| field.getGenericType().toString().equals("int"))
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
cursor.getInt(i));
else if (field.getGenericType().toString().equals("class java.lang.Long")
|| field.getGenericType().toString().equals("long"))
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
(long) cursor.getInt(i));
else if (field.getGenericType().toString().equals("class java.lang.Short")
|| field.getGenericType().toString().equals("short"))
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
(short) cursor.getInt(i));
else if (field.getGenericType().toString().equals("class java.lang.Byte")
|| field.getGenericType().toString().equals("byte"))
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
(byte) cursor.getInt(i));
else if (cursor.getType(i) == Cursor.FIELD_TYPE_STRING)
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
cursor.getString(i));
else if (cursor.getType(i) == Cursor.FIELD_TYPE_BLOB)
clazz.getMethod("set" + strColName, field.getType()).invoke(obj,
cursor.getBlob(i));
else
throw new DBException(null);
break;
objList.add(obj);
cursor.moveToNext();
return objList;
catch (Exception e)
e.printStackTrace();
throw new DBException(null);
return objList;
相反的,更新保存数据的时候,我们需要从实体对象取值。
public static <T> ContentValues putValue(Field[] fields, T entity) throws DBException
ContentValues values = new ContentValues();
for (Field field : fields)
if (!field.isAccessible())
field.setAccessible(true);
String strColName = ORMUtils.getColumnName(field);
if (strColName == null)
continue;
try
if (field.getGenericType().toString().equals("class java.lang.String"))
values.put(strColName, (String) (field.get(entity)));
else if (field.getGenericType().toString().equals("class java.lang.Boolean")
|| field.getGenericType().toString().equals("boolean"))
values.put(strColName, (((Boolean) (field.get(entity))) ? 1以上是关于手把手带你撸一套Android简易ORM框架的主要内容,如果未能解决你的问题,请参考以下文章