编写的通用数据库操作类

来源:互联网 发布:建站abc代理商 编辑:程序博客网 时间:2024/05/25 16:38

首先需要对象化要建表的对象,如News


通过一个interface,并定义增删改查方法,其传入的对象应当为泛型,只有这样才有通用性。需要一个
基础Dao类,DAO<M>,也使用了泛型,对应上面的实体类

public interface DAO<M> {//提供增删改查的接口long insert(M m);int delete(Serializable m);int update(M m);List<M> findAll();}

接着需要有抽象类实现该接口,这些接口就是具体的类的接口,即泛型实例化,如下:
public abstract class DaoSupport<M> implements DAO<M> {
  // 操作省略。。。。。。。。。。。。。。。。。。。。。。
}



需要让对象(News)和表建立对应关系,如获取表名和对象的关系(News类对应news表等等),或者 类中属性 和表的列 建立对应关系。
要实现上述操作,则可以通过自定义注解的方式完成。如下:
@TableName(MyDBHelper.TABLE_NEWS)public class News {@Primarykey@Column(MyDBHelper.COLUMN_NEWS_ID)private int id;@Column(MyDBHelper.COLUMN_NEWS_TITLE)private String title;//省略下面的set和get方法}

上面这段是一个简单的数据库实体类,其中的@TableName,@Primarykey,@Column都为自定义注解,其中@TableName的自定义注解如下:

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;//表明只能在类上使用该注解,还有如ElementType.FIELD,表示可以在字段上使用,ElementType.METHOD表示可以在方法上使用@Target(ElementType.TYPE) //表明可以在运行时获取该注解及其值,此外还有RetentionPolicy.SOURCE,表示在源代码阶段可以获取注解及其值@Retention(RetentionPolicy.RUNTIME) public @interface TableName {String value();}
而其他的注解,也和该注解大同小异。



问题一:如何获取表名

对数据库的操作需要表名,而传入的为泛型,这样如何获取表名呢?

其实在上面自定义的注解,已经给出了答案,

<pre name="code" class="html">@TableName(MyDBHelper.TABLE_NEWS)

这个表明该Class是与数据库的表对应的,对应的表名为
MyDBHelper.TABLE_NEWS

知道了这个,就很容易了,无非是获取泛型M的实例(即实例化一个M,如何实例化,请看后面)

接着就需要对该实例的注解进行解析,解析方式如下:

/** * 获取表名 */public String getTableName() {M m = getInstance();TableName annotation = m.getClass().getAnnotation(TableName.class);if (annotation != null) {// 说明有设置表名,则获取表名return annotation.value();}return "";}




问题二:如何将实体中的数据,按照对应关系导入到数据库中

其实可以观察一下普通的insert方法,如下:

// 普通写法ContentValues values = new ContentValues();values.put(MyDBHelper.COLUMN_NEWS_ID, news.getId());values.put(MyDBHelper.COLUMN_NEWS_TITLE, news.getTitle());return db.insert(MyDBHelper.TABLE_NEWS, null, values);
会发现News对象插入数据库,最重要的就是把News对象中的属性(field)给存放到ContentValues对象中。所以实现如下:

//通过自定义 fillValues方法,完成。

private void fillValues(M m, ContentValues values) {// 获取该类中添加的字段(不包括其父类的字段)Field[] declaredFields = m.getClass().getDeclaredFields();for (Field item : declaredFields) {// 有则表明为和表字段对应的属性Column annotation = item.getAnnotation(Column.class);if (annotation != null) {// 对应的表字段名// annotation.value().toString();item.setAccessible(true);// 对象的属性值// item.get(m);try {values.put(annotation.value(), item.get(m).toString());} catch (Exception e) {e.printStackTrace();}}}}


问题三: 在查询到数据库表数据后,如何取出?(查询时使用)

我们也可以观察一下,原查询语句:

        @Overridepublic List<News> findAll() {List list = null;Cursor cursor = db.query(getTableName(), null, null, null, null, null,null);if (cursor != null) {list = new ArrayList<New>();while (cursor.moveToNext()) {News m = new News();m.setTitle(cursor.getString(cursor.getColumnIndex("title")));
<span style="white-space:pre"></span>list.add(m);}cursor.close();}return list;}
会发现,其实最重要的就是  把Cursor中的数据给取出到实例化的对象中
则写方法如下:

/** * 把ContentValues中的值取出到M中 */private void fillField(Cursor cursor, M m) {Field[] fields = m.getClass().getDeclaredFields();for (Field item : fields) {item.setAccessible(true);Column column = item.getAnnotation(Column.class);if (column != null) {int columnIndex = cursor.getColumnIndex(column.value());String value = cursor.getString(columnIndex);try {item.set(m, value);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}}



问题四: 如何获取主键名和主键值(在修改删除等操作中需要)

上面有@Primarykey自定义注解,该注解就是为了声明哪个为主键的,所以实现如下:

/** * 获取该对象主键和主键值,为一个数组 *  * @param m * @return */private String[] getID(M m) {Field[] fields = m.getClass().getDeclaredFields();for (Field item : fields) {// 有则表明为和表字段对应的属性Primarykey annotation = item.getAnnotation(Primarykey.class);if (annotation != null) {// 对应的表字段名// annotation.value().toString();item.setAccessible(true);Column annotation2 = item.getAnnotation(Column.class);String[] results = null;if (annotation2 != null) {results = new String[2];results[0] = annotation2.value();try {results[1] = item.get(m).toString();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return results;}}}return null;}


问题五: 如何获取M泛型的实例

在上述中,获取表名,查询数据并返回等各种操作都需要使用到M泛型的实例。

那么如何获取泛型对象是哪个具体的类又如何实例化泛型对象呢?

由于是泛型无法通过如:

M m = new M();
或者
M m = M.class.newInstance();
的方式完成实例化,所以就需要通过特别的方式获取。如下:

/** * 获取到实体 */public M getInstance() {//返回该Object运行时类,例子如下://即如果一个类名为A继承了DaoSupport类(即本类),并泛型为News//class A extends DaoSupport<News>{////````//};//这时调用getClass()获取的为class com.luan.myNormalDB.DBTest$A//可以发现获取到的为A类本身,这样就可以通过该类获取其带参数的父类Class clazz = getClass();Log.i(TAG, clazz.getName());//获取的为class com.luan.myNormalDB.DaoSupport//clazz.getSuperclass();//获取的为com.luan.myNormalDB.DaoSupport<com.luan.myNormalDB.News>//clazz.getGenericSuperclass();Type type  =  clazz.getGenericSuperclass();if(type != null && type instanceof ParameterizedType){ParameterizedType pType = (ParameterizedType) type;//Returns an array of the actual type arguments for this type. //返回的结果为[class com.luan.myNormalDB.News]Type[] types = pType.getActualTypeArguments();try {return (M) ((Class) types[0]).newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return null;}

本程序思想来自黑马视频,我只是按照思想操作~






0 0
原创粉丝点击