import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.gzi.helper.Utils; import android.content.ContentValues; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; /** * 要维护的方法: * getValueByField(Cursor cur, Field field) * 根据field的类型从Cursor中取数据生成对应对象 * 当有新类型需求时要在分支中加入新的处理分支 * putValueToContentValues(String cn, Object value, Field f, ContentValues values) * 将对象转换成ContentValues接收的类型,也要处理 */ public class UtilDB extends BeanUtils{ /** * 根据Cursor生成对应的Bean并加到指定列表中 * * @param cur Cursor * * @param bc 对应Bean的class * * @param bl 一个存在的与存储生成bean类型对象的列表 */ public static <T> void addBeanToList(Cursor cur, Class<T> bc, ArrayList<T> bl) throws BeanException { if (bl == null) return;// 列表不存在则返回 if (cur != null && cur.getCount() > 0) { T bean = null; Object value = null; Field[] fs = bc.getDeclaredFields(); ColumnHolder ch = null; // 生成Bean的列表 while (cur.moveToNext()) { bean = newBeanByClass(bc); // 给bean实例赋值 for (Field f : fs) { ch = new ColumnHolder(f); // cn = ch.columnName; if (!ch.isColumn) continue;// 非数据库中的列忽略 value = getValueByField(cur, f,ch); setFieldValue(f, value, bean); } // 加入到列表中 bl.add(bean); } } } /** * 根据Cursor生成对应的Bean的列表 * * @param cur Cursor * * @param bc 对应Bean的class * * @return 生成的Bean的列表,如果cur没记录返回空list */ public static <T> ArrayList<T> getBeans(Cursor cur, Class<T> bc) throws BeanException { ArrayList<T> bl = new ArrayList<T>(); if (cur != null && cur.getCount() > 0) { addBeanToList(cur, bc, bl); } return bl; } /** * 根据field的类型从Cursor中生成对应的对象 * * @param cur 游标对象 * * @param field 属性域 * * @return Object 可能为null */ private static Object getValueByField(Cursor cur, Field field,ColumnHolder ch) throws BeanException { String columnName = ch.columnName; int ci = cur.getColumnIndex(columnName); if (ci == -1) return null;// 如果不存在此列则返回null Class fieldClass = field.getType(); // 根据属性类型从Cursor中获取值 if (fieldClass == String.class) return cur.getString(ci); else if (fieldClass == int.class || fieldClass == Integer.class) return cur.getInt(ci); else if (fieldClass == Date.class) { try { return Utils.parseChinaDate(cur.getString(ci), "yyyy-MM-dd HH:mm:ss"); } catch (Exception e) { // TODO Auto-generated catch block throw new BeanException("Date类型转换错误", e); } } // else if (fieldClass == ImageView.class) { // 处理图片 // return cur.getBlob(ci); // } else if (fieldClass == Long.class) return cur.getLong(ci); else if (fieldClass == Double.class) return cur.getDouble(ci); else if (fieldClass == Float.class) return cur.getFloat(ci); else if (fieldClass == Short.class) return cur.getShort(ci); return null; } private static class ColumnHolder { public String columnName; public boolean canNull = true; public boolean isKey = false; public boolean isColumn = true; public ColumnHolder(Field field) { // 根据注释获取属性对应的列名 Column column = field.getAnnotation(Column.class); if (column != null) { if (!column.value().equals(Column.defaultColumnName)) columnName = column.value(); else columnName = field.getName().toLowerCase(); canNull = column.canNull(); isKey = column.isKey(); isColumn = column.isColumn(); } else { // 没有注释则根据属性名小写化后的名字作列名 columnName = field.getName().toLowerCase(); } } } private static class TableHolder { public String tableName; public TableHolder(Class bc) { Table a = (Table) bc.getAnnotation(Table.class); if (a != null) tableName = a.value(); else tableName = bc.getName().toLowerCase(); } } private static void putValueToContentValues(String cn, Object value, Field f, ContentValues values) throws BeanException { Class fieldClass = f.getType(); // 根据属性类型为values赋值 if (fieldClass == String.class) values.put(cn, (String) value); else if (fieldClass == int.class || fieldClass == Integer.class) values.put(cn, (Integer) value); else if (fieldClass == Date.class) { try { values.put(cn, Utils.formatGMTDate((Date) value, "yyyy-MM-dd HH:mm:ss")); } catch (Exception e) { // TODO Auto-generated catch block throw new BeanException("Date类型转换错误", e); } } // else if (fieldClass == ImageView.class) { // 处理图片 // values.put(cn, (byte[])value); // } else if (fieldClass == Long.class) values.put(cn, (Long) value); else if (fieldClass == Double.class) values.put(cn, (Double) value); else if (fieldClass == Float.class) values.put(cn, (Float) value); else if (fieldClass == Short.class) values.put(cn, (Short) value); } /** * 插入bean列表到数据库中 * @param beans * @param db * @return * @throws BeanException */ public static <T> long InsertBeanList(List<T> beans, SQLiteDatabase db) throws BeanException { db.beginTransaction(); try { for (T bean : beans) { InsertBean(bean, db); } db.setTransactionSuccessful(); } catch (BeanException e) { // TODO Auto-generated catch block db.endTransaction(); throw e; } finally { db.endTransaction(); } return beans.size(); } /** * 将bean插入到数据库中,bean中有canNull=false注释的属性一定不能为空,否则抛出异常 * * @param bean * * @param db * * @return 插入行的id */ public static <T> long InsertBean(T bean, SQLiteDatabase db) throws BeanException { Field[] fs = bean.getClass().getDeclaredFields(); ContentValues values = new ContentValues(); String cn = null; Object value = null; ColumnHolder ch = null; for (Field f : fs) { ch = new ColumnHolder(f); cn = ch.columnName; if (!ch.isColumn) continue;// 非数据库中的列忽略 value = getFieldValue(bean, f); // 当不能为空的属性为空时,抛出异常 if (value == null && !ch.canNull) throw new BeanException("InsertBean属性不能为空:canNull=false注释,属性" + f.getName(), null); if (value == null) continue; putValueToContentValues(cn, value, f, values); } long id = -1; try { id = db.insertOrThrow(new TableHolder(bean.getClass()).tableName, null, values); } catch (SQLException e) { throw new BeanException("InsertBean插入记录不成功:" + e.getMessage(), e); } return id; } /** * 删除数据库中的记录,条件由传入的bean含有key注释的属性生成, 支持多列组成的主键, bean的其它属性不做处理,只处理含有key注释的属性 * * @param bean 含有主键的bean * * @param db 可写数据库 * * @return 删除记录数,这里一定为1,因为是主键定的条件 */ public static <T> int deleteBeanByKey(T bean, SQLiteDatabase db) throws BeanException { Field[] fs = bean.getClass().getDeclaredFields(); String cn = null; Object value = null; ColumnHolder ch = null; String where = null; for (Field f : fs) { ch = new ColumnHolder(f); if (!ch.isKey) continue;// 不是key主键不做处理 cn = ch.columnName; value = getFieldValue(bean, f); // 当值为空,抛出异常,因為到這一定是主鍵類型,不能為空 if (value == null) throw new BeanException("deleteBeanByKey属性不能为空:isKey=true注释属性" + f.getName(), null); where = getWhere(where, cn, value); } if (where == null) throw new BeanException("deleteBeanByKey删除记录:条件设置不正确where为空", null); int count = -1; count = db.delete(new TableHolder(bean.getClass()).tableName, where, null); return count; } /** * 对where追加项,格式为ColumnName=Value * * @param where 要追加的字符串 * * @param cn 列名 * * @param value 要追加的值 */ private static String getWhere(String where, String cn, Object value) { if (where == null) where = cn + "='" + String.valueOf(value) + "'"; else where += " and " + cn + "='" + String.valueOf(value) + "'"; return where; } /** * 更新数据库中的记录,条件由传入的bean含有key注释的属性生成, 支持多列组成的主键 * * 除了key注释的属性的其它属性,只要不为null就会被更新。 * * key注释的属性不可更新,因为那样就相当于新建了一条记录了。 * * @param bean 含有主键的bean * * @param db 可写数据库 * * @return 更新记录数,这里一定为1,因为是主键定的条件 */ public static <T> int updateBeanByKey(T bean, SQLiteDatabase db) throws BeanException { Field[] fs = bean.getClass().getDeclaredFields(); ContentValues values = new ContentValues(); String cn = null; Object value = null; ColumnHolder ch = null; String where = null; for (Field f : fs) { ch = new ColumnHolder(f); cn = ch.columnName; if (!ch.isColumn) continue;// 非数据库中的列忽略 value = getFieldValue(bean, f); if (ch.isKey) { // 当值为空,抛出异常,因為到這一定是主鍵類型,不能為空 if (value == null) throw new BeanException( "deleteBeanByKey属性不能为空:isKey=true注释属性" + f.getName(), null); where = getWhere(where, cn, value); } else { if (value == null) continue; putValueToContentValues(cn, value, f, values); } } if (where == null) throw new BeanException("updateBeanByKey更新记录:条件设置不正确where为空", null); if (values.size() <= 0) throw new BeanException("updateBeanByKey更新记录:没有要更新的值", null); int count = -1; count = db.update(new TableHolder(bean.getClass()).tableName, values, where, null); return count; } /** * 更新数据库中的记录,条件由传入的bean含有key注释的属性生成, 支持多列组成的主键 * * 除了key注释的属性的其它属性,只要不为null就会被更新。 * * key注释的属性不可更新,因为那样就相当于新建了一条记录了。 * * @param bean 含有主键的bean列表 * * @param db 可写数据库 * * @return 更新记录数,这里一定为1,因为是主键定的条件 */ public static <T> int updateBeanListByKey(ArrayList<T> beans, SQLiteDatabase db) throws BeanException { db.beginTransaction(); try { for (T bean : beans) { updateBeanByKey(bean, db); } db.setTransactionSuccessful(); } catch (BeanException e) { // TODO Auto-generated catch block db.endTransaction(); throw e; } finally { db.endTransaction(); } return beans.size(); } /** * 删除数据库中的记录,条件由传入的bean含有key注释的属性生成, 支持多列组成的主键, bean的其它属性不做处理,只处理含有key注释的属性 * * @param beans 含有主键的bean的列表 * * @param db 可写数据库 * * @return 删除记录数 */ public static <T> int deleteBeanListByKey(ArrayList<T> beans, SQLiteDatabase db) throws BeanException { db.beginTransaction(); try { for (T bean : beans) { deleteBeanByKey(bean, db); } db.setTransactionSuccessful(); } catch (BeanException e) { // TODO Auto-generated catch block db.endTransaction(); throw e; } finally { db.endTransaction(); } return beans.size(); } }