1.前言
作为一个java工程师,做点android开发的时候,自己做了个orm数据库的映射框架,使用比较方便,所以就放出来;
大家喜欢就拿去用,源码https://github.com/huitoukest/asorm;
很少用github,别见怪;
asorm1.0beta-->android Sqlite3 ORM;
1.本数据库支持自动创建表格,表的名字是你指定的Entity的名字;
如果要更改建表的名称,可以在你的Entity中复写BaseEntity中的public String getTableName()方法即可;
2.支持事务管理;
3.如果需要实现外键和存储过程需要自己编写相关sql语句;
4.不支持外键映射,只是支持对象和sql表之间的映射;
5.本数据库依赖于fastJson,请导入相关的包,对于Entity中不需要序列化的属性,请用@JSONField(serialize=false)注解;
2.开始使用
1.建立实体
这个和j2ee上使用Hibernate等框架是类似的,简历和数据库中表格相对应的类;
此类必须继承自BaseEntity;
示例:
public class User extends BaseEntity {
public Long Id;
public String Login_Name;
public String Password;
public String Real_Name;
public Long State;
public String Uid;
@Entity_FieldProperty(FieldType=FieldType.JsonObject,cls=Sys_User_Info.class)
public Sys_User_Info UserInfo;
@Override
public Long getPrimaryKeyValue() {
return Id;
}
@Override
public String getPrimaryKeyName() {
return "Id";
}
}
其中你必须Override其中的两个方法public Long getPrimaryKeyValue()和public String getPrimaryKeyName(),返回此实体的主键值与主键名称;
此实体对应的表的名称默认为其类名,不可更改;
主键只能是Long或者int类型;
默认支持的属性类型有:int,Integer,Short,short,Double,double,Float,float,Date,String,Long,long,Byte,byte;以及注解过的对象
对于实体Entity类的属性,可以通过@Entity_FieldProperty注解来对其映射方式做说明;
对于Entity_FieldProperty的FieldType=FieldType.XXX有四种方式;
JsonList,JsonObject,Base,Transient,具体功能见下面代码说明;
注解内容:
/**
* 指定当前Entity中的属性的属性,即自生的类别和转换的方式
* JsonList,JsonObject,Base,Transient
* 当FieldType.Base的时候,将会按照默认识别的类型使用,即此时的cls属性不会生效
* JsonList,JsonObject表示此对象需要转换为一个json对象或者字符串;
* Transient表示此对象,不进行数据库的存和取操作,选择Transient的时候,cls属性不会生效
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity_FieldProperty {
/**
* 指定一个类型是FieldType的,表现为FieldType=默认为FieldType.Base的Annotation
* @return
*/
FieldType FieldType() default FieldType.Base;
/**
* 指定一个类型是Class的,表现为cls=默认为String.class的Annotation
* @return
*/
Class<?> cls() default String.class;
/**
* 指定当前属性的类型
*
*/
public enum FieldType{
JsonList,JsonObject,Base,Transient;
};
}
对于对象,本框架是以json方式序列化属性为字符串之后存储到数据库的;
2.初始化数据库和asorm
在android使用此框架操作数据之前,需要对数据库进行初始化;
调用DataBaseManager.initializeInstance(Context c,EntityInfos entityInfos);方法来初始化数据库和asorm;
只有初始化之后才可以使用和数据库相关的操作;建议在app启动的第一个类中最先调用此方法;并传入Application 的context
EntityInfos是一个接口,我们需要实现此接口,此接口包含如下方法:
/**
* 返回Entity类,你的Entity类的set
* @return
*/
public HashSet<Class<? extends BaseEntity>> getEntityClasses();
/**
* 返回数据库的名称,如"123";
* @return
*/
public String getDataBaseName();
/**
* 返回数据库的版本,如1;
* @return
*/
public int getDataBaseVersion();
/**
* 当数据库版本变化的时候先调用此方法;
* 然后返回true表示调用默认方法,删除所有数据然后重新建立表;
* 然会false表示不调用默认方法,此方法不会自己管理事务;
* @return
*/
public boolean onDataBaseVersionChange(SQLiteDatabase db);
示例:
public class MyEntityInfos implements EntityInfos{
@Override
public HashSet<Class<? extends BaseEntity>> getEntityClasses() {
HashSet<Class<? extends BaseEntity>> set=new HashSet<Class<? extends BaseEntity>>();
set.add(User.class);
return set;
}
@Override
public String getDataBaseName() {
return "dview242.db";
}
@Override
public int getDataBaseVersion() {
return 1;
}
@Override
public boolean onDataBaseVersionChange(SQLiteDatabase db) {
return true;
}
}
初始化中,主要做如下工作:
建立和Entity对应的表,同时保持表名称和主键信息;
之后我们可以调用EntityManager.getTableNameByCls(Class<? extends BaseEntity> cls);方法来获取表明,
同样,可以调用EntityManager的public static String getPrimaryKeyNameByCls(Class<? extends BaseEntity> cls);方法来获取主键名称;
3.建立service层;
一个app应该有数据库层;控制层;表现层;
而asorm框架主要封装了数据层的操作的dao层,我们需要在控制层做好事务控制;
框架要求,所有的和数据库操作相关的顶层封装都需要建立事务的控制下,
意思就是你操作数据库的任何操作,都必须使用此框架提供的事务控制方式来控制事务,同时不要自己打开关闭数据库和事务,而是应该交给asorm来控制;
第一步:建立Service方法接口,并继承自BaseServiceI接口:
public interface LoginTypeServiceI extends BaseServiceI{
@SqliteTransaction(Type=TransActionType.Write)
public abstract LoginType getLoginType() throws Exception;
@SqliteTransaction(Type=TransActionType.Write)
public abstract boolean saveOrUpdate(LoginType loginType) throws Exception;
}
public interface BaseServiceI {
@SqliteTransaction(Type=TransActionType.Write)
public BaseEntityDaoI getBaseEntityDao();
}
BaseServiceI的主要作用是返回BaseEntityDaoI这个接口;
第二步:建立Service的实现类;
实现自定的service接口,并实现其方法;
对于public BaseEntityDaoI getBaseEntityDao();可以继承类BaseService,此类中复写了此方法;
public class BaseService implements BaseServiceI{
@SqliteTransaction(Type=TransActionType.Write)
public BaseEntityDaoI getBaseEntityDao(){
return BaseEntityDao.getBaseEntityDaoI();
}
}
当然,用户也可以自己复写方法,内容如下 BaseEntityDao.getBaseEntityDaoI();
对于BaseEntityDaoI系统提供的是BaseEntityDao实现,用户熟读源码后可以自行实现内容;
第三步:注解事务
利用BaseEntityDao我们可以对对象进行crud等操作;在操作之前,需要对方法事务进行管理;
在此方法对应的接口的方法上,用注解来说明事物;
public interface LoginTypeServiceI extends BaseServiceI{
@SqliteTransaction(Type=TransActionType.Read)
public abstract LoginType getLoginType() throws Exception;
@SqliteTransaction(Type=TransActionType.Write)
public abstract boolean saveOrUpdate(LoginType loginType) throws Exception;
}
目前支持Read和Write两种方式,底层的实现实际上都是得到一个可写的数据库连接;
不同的是对事物的管理不同;对于读写方式,请选择Write
第四步:操作对象
对Entity对象进行增删改查等操作,由于方法之间事务的独立性,service层也可以考虑做成单例;
示例:
public class LoginTypeService implements LoginTypeServiceI {
private BaseEntityDaoI baseDao;
private LoginTypeService(){
baseDao=BaseEntityDao.getBaseEntityDaoI();
}
public static LoginTypeServiceI getNewProxyInstance(){
return (LoginTypeServiceI) MySqliteTransactionProxy.getSqliteTransactionProxy(LoginTypeServiceI.class,new LoginTypeService());
}
@Override
public LoginType getLoginType() throws Exception{
LoginType lt=new LoginType();
lt.setId(1L);
try {
lt=baseDao.get(lt);
return lt;
} catch (Exception e) {
throw new ReturnException(null);
}
}
@Override
public boolean saveOrUpdate(LoginType loginType) throws Exception{
if(loginType==null||loginType.getPrimaryKeyValue()==null)
return false;
try {
baseDao.saveOrUpdate(loginType);
return true;
} catch (Exception e) {
throw new ReturnException(false);
}
}
@Override
public BaseEntityDaoI getBaseEntityDao() {
return baseDao;
}
}
说明:
在显示层,一般是activity中;我们通过LoginTypeServiceI service=(LoginTypeServiceI)
MySqliteTransactionProxy.getSqliteTransactionProxy(LoginTypeServiceI.class,new LoginTypeService());
方式来获取servic层;即用MySqliteTransactionProxy.getSqliteTransactionProxy(service接口类,service实现类)得到service接口的一个实现来获取service;
然后通过返回的接口示例来操作数据库;
若果想要在serive层方法执行的时候发生异常的时候返回一个值;可以使用throw new ReturnException(XXXX);
这样将会回滚当前的事务,并返回指定的值;
示例:
public class UserLoginActivity extends BaseFragmentActivity {
private UserServiceI userService;</span>
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_userlogin);
userService=(UserServiceI) MySqliteTransactionProxy.getSqliteTransactionProxy(UserServiceI.class,new UserService());
initView();
}
public void initView(){
......
}
public void user_login_click(View v){
switch (v.getId()) {
case R.id.submit_button_userlogin:
{
<span style="color:#ff0000;">userService.LoginFromServer(userName,password,webServiceCallBack);</span>
}
break;
case .......
default:
break;
}
}
}
3.BaseDaoI中方法一览
BaseDao中方法的实现是花了一点时间和精力的,有兴趣的童鞋可以去查看;没兴趣的可以直接使用;
public interface BaseEntityDaoI {
public abstract SQLiteDatabase getDataBase();
/**
* 得到当前的最大的id号码的值
* @param db
* @return
*/
public abstract <T extends BaseEntity> Long getMaxId(T t);
/**
* 得到当前的最小的id号码的值
* @param db
* @return
*/
public abstract <T extends BaseEntity> Long getMinId(T t);
/**
* 得到当前的的记录总数
* @param db
* @return
*/
public abstract <T extends BaseEntity> Long getCount(Class<T> cls);
/**
*得到除开指定名称的属性列
*/
public abstract <T extends BaseEntity> String[] getEntityColumnNames(
Class<T> cls, Boolean isRepacePrimaryKeyName,
String... exceptCoulums);
/**失败返回null
* 传入代Id值的Entity的值实例
* @param t 返回t
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> T get(Class<T> cls, String id)
throws Exception;
/**失败返回null
* 传入代Id值的Entity的值实例
* @param t 返回t
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> T get(T t) throws Exception;
/**手动的条件搜索
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> T get(Class<T> cls,
String[] columns, String selection, String[] selectionArgs,
String orderBy) throws Exception;
/**失败返回null
* 传入代Id值的Entity的值实例
* @param t 返回t
* @param exceptCoulums 不需要取出的数据列的名称
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> T get(Class<T> cls, String id,
String... exceptCoulums) throws Exception;
/**
*
* 失败返回空数组
* @param db
* @param cls
* @param selection
* @param selectionArgs
* @param orderBy
* @param limit select * from table_name limit N,M //N序号从0开始
* @param exceptCoulums 指定不从数据库取出的列
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> List<T> getList(Class<T> cls,
String selection, String[] selectionArgs, String orderBy,
String limit, String... exceptCoulums) throws Exception;
/**
* 失败返回空数组
* @param db
* @param cls
*@param selection
* @param selectionArgs
* @param orderBy
* @param limit select * from table_name limit N,M //N序号从0开始
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> List<T> getList(Class<T> cls,
String selection, String[] selectionArgs, String orderBy,
String limit) throws Exception;
/**
* 获取数据库中的所有的记录
* @param db
* @param cls
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> List<T> getList(Class<T> cls)
throws Exception;
public abstract <T extends BaseEntity> void saveOrUpdate(T t)
throws Exception;
/**
*
* @param t
* @return 插入返回1
* @param columnName 如果指定的字段,有相同的值存在于数据库,那么就更新数据库,否则保存
* @throws Exception
*/
public abstract <T extends BaseEntity> void saveOrUpdate(T t,
String columnName) throws Exception;
/**
* 先删除,后保存,没有则不删除
* @param db
* @param t
* @throws Exception
*/
public abstract <T extends BaseEntity> void deleteAndSave(T t)
throws Exception;
/**
*
* @param db
* @param list
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> void saveOrUpdateList(List<T> list)
throws Exception;
/**
*
* @param db
* @param list
* @param column 指定列的值相同就更新,否则就保存
* @throws Exception
*/
public abstract <T extends BaseEntity> void saveOrUpdateList(List<T> list,
String column) throws Exception;
/**
*删除后保存所有
* @param db
* @param list
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> void deleteAndSaveList(List<T> list)
throws Exception;
public abstract <T extends BaseEntity> int update(T t) throws Exception;
/**
*
* @param t
* @param notUpdateColumns 不需要更新的字段名称的数组
* @return
* @throws Exception
*/
public abstract <T extends BaseEntity> int update(T t,
String[] notUpdateColumns) throws Exception;
public abstract <T extends BaseEntity> int save(T t) throws Exception;
public abstract <T extends BaseEntity> int delete(Class<T> cls, String id)
throws Exception;
public abstract <T extends BaseEntity> int delete(T t) throws Exception;
public abstract <T extends BaseEntity> int deleteList(Class<T> cls,
String ids) throws Exception;
public abstract <T extends BaseEntity> int deleteList(List<T> ts)
throws Exception;
public abstract <T extends BaseEntity> int deleteAll(Class<T> cls)
throws Exception;
/**
*
* @param db
* @param sqlString
* @param selectionArgs sql中?占位符的参数
* @param columns 需要出去的列的名称,没有会赋值null;取出的列只支持float/string/blob/string/null这几种类型;
* *其中二进制会转换成为byte[]类型;除开这些类型外,系统会默认用string来取出数据
* @return List<Object[]>
*/
public abstract <T extends BaseEntity> List<Object[]> getColumns(
String sqlString, String[] selectionArgs, String... columns);
/**
* 判断一个属性是否是静态变量,此类暂时不用
* @param field
*/
public abstract boolean isStaticField(Field field);
//通过Cursor自动将值赋值到实体
public abstract <T extends BaseEntity> T initFromCursor(Cursor c,
Class<T> cls) throws IllegalAccessException,
IllegalArgumentException, InstantiationException;
public abstract <T extends BaseEntity> T initFromCursor(Cursor c, T t)
throws IllegalAccessException, IllegalArgumentException,
InstantiationException;
public abstract <T extends BaseEntity> ContentValues getContentValues(T t)
throws IllegalAccessException, IllegalArgumentException;
/**
* 返回该类属性的键值对,键和值均为String类型
* @return
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public abstract <T extends BaseEntity> Map<String, Object> getMapValues(T t)
throws IllegalAccessException, IllegalArgumentException;
public abstract <T extends BaseEntity> void saveToDataBase(T t)
throws Exception;
public abstract <T extends BaseEntity> void updateToDataBase(T t)
throws Exception;
/**
*
* @param tableName
* @param db
* @param columnName 指定此此表的一个列名称,更新所有相同的记录
* @throws Exception
*/
public abstract <T extends BaseEntity> void updateToDataBaseByColumn(T t,
String columnName) throws Exception;
/**
*
* @param tableName
* @param data
* @param notUpdateColumns 不需要跟新的字段,区分大小写
* @throws Exception
*/
public abstract <T extends BaseEntity> void updateToDataBase(T t,
String[] notUpdateColumns) throws Exception;
}
4.小结
1.本框架为非正式版,肯定有不少的bug,作者也没有全部测试,有bug的可以反馈留言;
2.此版本通过同步锁对数据库写操作进行阻塞,理论上并不好,实际高并发或者大量输入写入的不推荐使用;
3.下一个版本想要实现的功能:
(1)采用回调的方式来进行数据库的读写操作;
(2)采用一个表一个数据库的方式提高并发写操作;
4.文档可能不全,不过源码注释还是很多,建议看看源码即可
5.附上jar包地址
http://download.youkuaiyun.com/detail/huitoukest/9475537