反射实现Android Sqlite Orm

博主分享了一篇关于使用反射实现Android ORM的文章,虽然认为在Android上ORM意义有限,但作为练习项目,他创建了一个可以根据实体对象自动建表并自动保存数据到SQLite数据库的简单ORM。代码主要涉及在Application中注册实体,然后在SqliteOpenHelper的OnCreate方法中通过反射构建建表SQL,以及反射将对象属性转换为ContentValues进行插入操作。
摘要由CSDN通过智能技术生成

昨天相当无聊,就动手写了一个Orm。其实个人觉得在Android上写Orm意义不大,Android自带的ContentValues对象和SqliteDatabase.Insert(...)等方法已经够给不喜欢写sql语句的同学使用了。不过无聊就写了,权当练练手吧~~~

【原创文章,转载请声明】转自http://blog.csdn.net/allen_704/article/details/21225371

以下程序实现了根据实体对象自动建表,以及Orm的save(Object obj)方法自动插入对应的表,没有用注解,注解加上会更灵活一些,懒得搞了。

第一个功能:根据实体建表。思路是在Application中将要建表的实体注册到数据库类中,在SqliteOpenHelper的OnCreate方法中查找出所有已注册的实体类,通过反射拿到所有属性拼接建表Sql语句。上代码:

/**
 * @author heg
 * @version 创建时间:2014-3-13 下午4:24:58
 * @description: 注册需要自动生成数据库表的实体类,会将实体所有属性自动生成表
 */
public  class OrmApplication extends Application {

	private String TAG = OrmApplication.class.getName();


	@Override
	public void onCreate() {
		Log.i(TAG , "application created");
		registerEntities();
		super.onCreate();
	}
	
	
	/**
	 * 注册需要自动生成数据库表的实体类
	 */
	protected  void registerEntities(){
		BaseDatabase.registerEntities(User.class);
		//TODO add entities here
	}
}

public static class SqliteHelper extends SQLiteOpenHelper {

		@Override
		public void onCreate(SQLiteDatabase db) {
			createTables(db);
		}
}
public static void createTables(SQLiteDatabase db) {
		for(Class<?> clazz : entities){
			String sql = EntityUtil.entityToCreateTableSql(clazz);
			if(sql!=null &&! "".equals(sql))
				db.execSQL(sql);
		}
	}

/**
	 * 通过实体的基本属性创建建数据表语句<br>
	 * 
	 * @param clazz
	 * @return
	 */
	public static String entityToCreateTableSql(Class<?> clazz) {
		StringBuffer sb = new StringBuffer();
		Field[] fields = clazz.getDeclaredFields();
		if (fields.length == 0)
			return null;
		sb.append("CREATE TABLE IF NOT EXISTS ");
		sb.append(clazz.getSimpleName().toLowerCase());
		sb.append(" (");
		sb.append("_id").append(" INTEGER PRIMARY KEY,");
		for (Field f : fields) {
			String fieldType = f.getType().getSimpleName();
			String fieldName = f.getName().toLowerCase();
			if ("String".equals(fieldType)) {
				sb.append(fieldName).append(" TEXT,");
			} else if ("Date".equals(fieldType)) {// 日期当做String来处理
				sb.append(fieldName).append(" TEXT,");
			} else if ("Integer".equals(fieldType) || "int".equals(fieldType)) {
				sb.append(fieldName).append(" INT,");
			} else if ("Long".equalsIgnoreCase(fieldType)) {
				sb.append(fieldName).append(" BIGINT,");
			} else if ("Double".equalsIgnoreCase(fieldType)) {
				sb.append(fieldName).append(" DOUBLE,");
			} else if ("Float".equalsIgnoreCase(fieldType)) {
				sb.append(fieldName).append(" FLOAT,");
			} else if ("Boolean".equalsIgnoreCase(fieldType)) {
				sb.append(fieldName).append(" BOOLEAN,");
			} else if ("Char".equalsIgnoreCase(fieldType)) {
				sb.append(fieldName).append(" CHAR,");
			} else if ("Byte".equalsIgnoreCase(fieldType)) {
				sb.append(fieldName).append(" TINYINT,");
			} else {// 后续Object等类型拓展

			}
		}
		sb.deleteCharAt(sb.lastIndexOf(","));
		sb.append(");");
		Log.i(TAG, clazz.getSimpleName() + " create table sql = " + sb.toString());
		return sb.toString();
	}


第二个就是save方法了,也是利用反射将object所有属性值转成ContectValues对象丢给SqliteDatabase,insert方法,懒得拼接sql语句了。上代码:

package com.heg.lib.db.orm;

import com.heg.lib.db.orm.BaseDatabase.SqliteHelper;
import com.heg.lib.utils.EntityUtil;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

/**
 * @author heg
 * @version 创建时间:2014-3-13 下午6:07:30
 * @description: TODO
 */
public class Dao {
	private static final String TAG = Dao.class.getName();
	private static Object mutex = new Object();
	private SqliteHelper dbhelper = null;
	private SQLiteDatabase db = null;
	private boolean reserved = false;
	
	public Dao(Context ctx) {
		dbhelper = SqliteHelper.getInstance(ctx);
	}
	
	public boolean save(Object obj) {
		synchronized (mutex) {
			if (!BaseDatabase.isEntityRegisted(obj.getClass()))
				return false;
			try {
				if (reserve()) {
					long ret = db.insert(obj.getClass().getSimpleName(), null,
							EntityUtil.entityToContentValues(obj));
					Log.i(TAG, "save ret = " + ret);
					if (ret != -1)
						return true;
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				//此处按照我的本意是想关闭数据库的,不过报了个奇怪的错,
				//unable to close due to unfinalised statements。
				//网上查了都是些各种抄的没用的答案,暂时就不关闭了!
				//有知道原因的同学麻烦告知一下了,谢谢~~
//				release();
			}
			return false;
		}
	}
	
	
	private boolean reserve() {
		synchronized (mutex) {
			if (!reserved) {
				if ((db = dbhelper.getWritableDatabase()) != null) {
					reserved = true;
					return true;
				}
			} else {
				return true;
			}
		}
		return false;
	}

	private void release() {
		synchronized (mutex) {
			Log.i(TAG, "release========");
			if (reserved) {
				db.releaseReference();
				reserved = false;
			}
		}
	}
	
	
	
}

/**
	 * entity to ContentValues
	 * 
	 * @param obj
	 * @return
	 */
	public static ContentValues entityToContentValues(Object obj) {
		Class<?> cls = obj.getClass();
		ContentValues cv = new ContentValues();
		// 取出entity里的所有方法
		Method[] methods = cls.getDeclaredMethods();
		Field[] fields = cls.getDeclaredFields();
		for (Field field : fields) {
			try {
				String fieldType = field.getType().getSimpleName();
				String fieldGetName = parseMethodName(field.getName(), "get");
				if (!haveMethod(methods, fieldGetName)) {
					continue;
				}
				Method fieldGetMet = cls.getMethod(fieldGetName, new Class[] {});
				Object fieldVal = fieldGetMet.invoke(obj, new Object[] {});
				if (null == fieldVal) {
					continue;
				}
				String value = String.valueOf(fieldVal);
				if ("String".equals(fieldType)) {
					cv.put(toDbColumName(field.getName()), value);
				} else if ("Date".equals(fieldType)) {// 日期当做String来处理
					cv.put(toDbColumName(field.getName()), value);
				} else if ("Integer".equals(fieldType) || "int".equals(fieldType)) {
					cv.put(toDbColumName(field.getName()), Integer.parseInt(value));
				} else if ("Long".equalsIgnoreCase(fieldType)) {
					cv.put(toDbColumName(field.getName()), Long.parseLong(value));
				} else if ("Double".equalsIgnoreCase(fieldType)) {
					cv.put(toDbColumName(field.getName()), value);
				} else if ("Float".equalsIgnoreCase(fieldType)) {
					cv.put(toDbColumName(field.getName()), value);
				} else if ("Boolean".equalsIgnoreCase(fieldType)) {
					cv.put(toDbColumName(field.getName()), Integer.parseInt(value));
				} else if ("Char".equalsIgnoreCase(fieldType)) {
					cv.put(toDbColumName(field.getName()), value);
				} else if ("Byte".equalsIgnoreCase(fieldType)) {
					cv.put(toDbColumName(field.getName()), Integer.parseInt(value));
				} else {// 后续Object等类型拓展

				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return cv;

	}


差不多就这样了,工程代码路径 SimpleOrm 有需要的同学可以下来看看。 

【原创文章,转载请声明】转自http://blog.csdn.net/allen_704/article/details/21225371

一个简单的基于AndroidSqlite数据库的操作封装,它有如下的好处:便捷地创建和增添字段灵活的数据类型处理通过操作对象来insert或者update记录支持多种查询方式,支持多自定义的复杂查询,支持分页查询支持事务快速开始:    1. 设计:@Table(name="t_user") public class UserModel {     @Table.Column(name="user_id",type=Column.TYPE_INTEGER,isPrimaryKey=true)     public Integer userId;     @Table.Column(name="user_name",type=Column.TYPE_STRING,isNull=false)     public String userName;     @Table.Column(name="born_date",type=Column.TYPE_TIMESTAMP)     public Date bornDate;     @Table.Column(name="pictrue",type=Column.TYPE_BLOB)     public byte[] pictrue;     @Table.Column(name="is_login",type=Column.TYPE_BOOLEAN)     public Boolean isLogin;     @Table.Column(name="weight",type=Column.TYPE_DOUBLE)     public Double weight; }2. 初始化对象:SQLiteDatabase db = context.openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null); DbSqlite dbSqlite = new DbSqlite(db); IBaseDao userDAO = DaoFactory.createGenericDao(dbSqlite, UserModel.class);3. 创建:userDAO.createTable(); 4. Insert 记录:UserModel user = new UserModel(); user.userName = "darcy"; user.isLogin = true; user.weight = 60.5; user.bornDate = new Date(); byte[] picture = {0x1,0x2,0x3,0x4}; user.pictrue = picture; userDAO.insert(user);5. Update 记录:UserModel user = new UserModel(); user.weight = 88.0; userDAO.update(user, "user_name=?", "darcy");6. 查询://单条结果查询 UserModel user = userDAO.queryFirstRecord("user_name=?", "darcy"); //一般查询 List userList = userDAO.query("user_name=? and weight > ?", "darcy" , "60"); //分页查询 PagingList pagingList = userDAO.pagingQuery(null, null, 1, 3);7. 事务支持:DBTransaction.transact(mDb, new DBTransaction.DBTransactionInterface() {         @Override         public void onTransact() {             // to do                 } };8. 更新(目前只支持添加字段)@Table(name="t_user" , version=2) //修改版本 public class UserModel {     //members above...     //new columns     @Table.Column(name="new_column_1",type=Column.TYPE_INTEGER)     public Integer newColumn;     @Table.Column(name="new_column_2",type=Column.TYPE_INTEGER)     public Integer newColumn2; } userDAO.updateTable();缺点和不足:还没支持多对一或者一多的关系没支持联合主键没支持的外键设计其他...实例:SqliteLookup(Android内查看Sqlite数据库利器): https://github.com/YeDaxia/SqliteLookup 标签:SQLiteUtils
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值