为什么要用ORM

在开发Android的过程中,我们基本上都会用到sqlite数据库,一般省事的情况下都是使用网上的一些orm框架操作sqlite数据库,比较有名的ORMLite、GreenDao和Active Android等。一般情况下,当预料到数据库会复杂到某个程度,就有必要引入数据库的ORM框架,这样可以大大降低开发和维护的成本。当然,站在巨人的肩膀上,选择好的开源库更可以事半功倍。选择怎么样的ORM Android上的ORM框架不少:GreenDao, Active Android,Schematic,Ollie,Sprinkles...到底应该如何选择?这些ORM框架用到的实现方式主要有几种:1.注解(运行时 Annotation,编译时 Annotation)2.反射3.直接生成代码这里简单地直接说结论:通过运行时注解或反射去建立数据表和实体的关系会导致性能比较低。从性能角度出发,应该选择使用编译时注解或代码生成的框架。当然,成熟程度,文档资料等也是考量点。

感兴趣的朋友可以自己去试试,今天我要说的是自己在android sdk 为我们提供的基础上进行自己的封装,达到方便高效的目的。

Android提供了一个SQLiteOpenHelper类来可以很方便的操作数据库,继承和扩展SQLiteOpenHelper类主要做的工作就是重写以下两个方法。        onCreate: 当数据库被首次创建时执行该方法,一般将创建表等初始化操作在该方法中执行。        onUpgrade:当打开数据库时传入的版本号与当前的版本号不同时会调用该方法。

想要封装自己的数据库操作类就要继承SQLiteOpenHelper,到达自己的目的了,首先看下我写的。

[java] 
     view plain 
      copy 
      
   
 
  
1. public class DBHelper extends
2. private static Logger logger = LoggerFactory.getLogger(DBHelper.class);  
3. private final static String DATABASE_PATH = Environment.getExternalStorageDirectory() + "/";  
4. private
5. private int
6.   
7. public DBHelper(Context context, String dbName, int
8. super(context, dbName, (SQLiteDatabase.CursorFactory)null, initVersion);  
9. this.context = context;  
10. this.dbVersion = initVersion;  
11.     }  
12.   
13. @Override
14. public void
15. for(int i = 1; i <= this.dbVersion; ++i) {  
16. this.upgradeSqlData(db, i, false);  
17.         }  
18.     }  
19.   
20. private void upgradeSqlData(SQLiteDatabase db, int version, boolean
21.         String fileName;  
22. if(isDowngrade) {  
23. "_" + version + "_db.sql";  
24. else
25. "_db.sql";  
26.         }  
27.   
28. null;  
29.         db.beginTransaction();  
30.   
31. try
32. this.context.getAssets().open(fileName);  
33. new InputStreamReader(e, "UTF-8");  
34. new
35.             String line = bufferedReader.readLine();  
36. new
37.   
38. while(true) {  
39. while(line != null) {  
40.                     line = line.trim();  
41. if(!"".equals(line) && line.charAt(0) != 47 && line.charAt(0) != 45) {  
42. boolean middleIndex = true;  
43. int
44. if((middleIndex1 = line.lastIndexOf("--")) != -1) {  
45. 0, middleIndex1);  
46.                         }  
47.   
48.                         sb.append(line);  
49.                         String sql = sb.toString();  
50. if(!"".equals(sql) && sql.charAt(sql.length() - 1) == 59) {  
51. "load sql:{}", sql);  
52. 0, sql.indexOf(59)));  
53. new
54.                         }  
55.   
56.                         line = bufferedReader.readLine();  
57. else
58.                         line = bufferedReader.readLine();  
59.                     }  
60.                 }  
61.   
62.                 db.setTransactionSuccessful();  
63. "load file {} success.", fileName);  
64. "TAG","load file {} success."
65. break;  
66.             }  
67. catch
68. "load file {} failed.", fileName, var20);  
69. "TAG","load file {} success."
70. finally
71. try
72. if(bufferedReader != null) {  
73.                     bufferedReader.close();  
74.                 }  
75.   
76.                 db.endTransaction();  
77. catch
78.                 ;  
79.             }  
80.   
81.         }  
82.   
83.     }  
84.   
85. @Override
86. public void onUpgrade(SQLiteDatabase db, int oldVersion, int
87. for(int i = oldVersion + 1; i <= newVersion; ++i) {  
88. this.upgradeSqlData(db, i, false);  
89.         }  
90.     }  
91.   
92. public void onDowngrade(SQLiteDatabase db, int oldVersion, int
93. for(int i = oldVersion - 1; i >= newVersion; --i) {  
94. this.upgradeSqlData(db, i, false);  
95.         }  
96.   
97.     }  
98.   
99. //    @Override
100. //    public SQLiteDatabase getWritableDatabase() {
101. //        File file = new File(DATABASE_PATH + "dbtest");
102. //        if (!file.exists()) {
103. //            file.mkdirs();
104. //
105. //        }
106. //        File dbFile = new File(file,"mydb.db");
107. //        if (!dbFile.exists())
108. //            try {
109. //                dbFile.createNewFile();
110. //            } catch (IOException e) {
111. //                e.printStackTrace();
112. //            }
113. //        return SQLiteDatabase.openOrCreateDatabase(dbFile,null);
114. //    }
115. //
116. //    @Override
117. //    public SQLiteDatabase getReadableDatabase() {
118. //        return getWritableDatabase();
119. //    }
120. }

重写了oncreate()方法和onUpgrade()方法,前面也说了两个方法的用途,数据库初次创建的时候,肯定是要建数据库建表,所以在onCreate()的方法执行了创建表的sql语句,

因为默认了数据库的创建路径,所以我们是不需要手动的创建数据库文件的,如果你想制定数据库创建的路径,那么就得自己创建数据库文件了,类中注释掉的代码就是指定在sdcard中创建数据库文件的代码。再说一说sql建表语句,我将建表的sql语句写到了android目录下的assets文件夹下面,在该文件夹下新建一个文本文件,后缀改为.sql其它格式也行,但是要注意自己代码中要一致。

[java] 
    view plain 
     copy 
     
  
 
 
1. -- Describe USER  
2. CREATE TABLE cdd_user (  
3.   id        INTEGER PRIMARY KEY AUTOINCREMENT,  
4.   user_name        TEXT,         --对应userCode  
5.   user_age       TEXT         --对应userName  
6. );

这里要说明一下,这个.sql文件的命名是要有一定规则的,以数字开头然后下划线然后加上db,如 1_db.sql 当然这只是我自己定义的规则方便读取,你们也可以定义自己的规则,但是DBHelper中的方法就得自己修改了,不然是找不到文件的。1_db.sql的1代表了当前的数据库版本号是1,每次相对于上个版本增加了表就新增加一个sql文件,命名前的数字比上次的sql文件加1,这样数据库就能自动创建表新增表了,而不需要我们删除app再安装,这就是数据库版本号的用处。

下面就说说数据库dao,android sdk已经封装好了插入,删除,更新,查询方法,但是这样每次都写一大堆东西太冗余了,我们简单的封装一下就好多了,首先写个基类其中包含增删改查。

[java] 
    view plain 
     copy 
     
  
 
 
1. public class
2. protected Logger logger = LoggerFactory.getLogger(this.getClass());  
3. protected
4.   
5. public
6.         dbHelper = DBUtil.getInstance(context).getDbHelper();  
7.     }  
8.   
9. /**
10.      * 数据插入
11.      * @param table
12.      * @param nullColumnHack
13.      * @param values
14.      * @return
15.      */
16. public long
17. long ret = 0;  
18.         SQLiteDatabase database = dbHelper.getWritableDatabase();  
19.         database.beginTransaction();  
20. try
21.             ret = database.insert(table, nullColumnHack, values);  
22.             database.setTransactionSuccessful();  
23. catch
24. "insert error. ", e);  
25. finally
26.             database.endTransaction();  
27.         }  
28. return
29.     }  
30.   
31. /**
32.      * 数据查询
33.      * @param table
34.      * @param columns
35.      * @param selection
36.      * @param selectionArgs
37.      * @param groupBy
38.      * @param having
39.      * @param orderBy
40.      * @param limit
41.      * @param <T>
42.      * @return
43.      */
44. public
45. new
46. null;  
47. try
48. if (limit != null) {  
49. "");  
50. else
51.                 cursor = dbHelper.getReadableDatabase().query(table, columns, selection, selectionArgs, groupBy, having, orderBy);  
52.             }  
53.             results = queryResult(cursor);  
54. catch
55. "query error. ", e);  
56. finally
57. if (cursor != null) {  
58.                 cursor.close();  
59.             }  
60.         }  
61. return
62.     }  
63.   
64. /**
65.      * 转换为对象
66.      * @param cursor
67.      * @param <T>
68.      * @return
69.      */
70. public
71. throw new RuntimeException("Please overwrite method.");  
72.     }  
73.   
74. /**
75.      * 数据更新
76.      * @param table
77.      * @param values
78.      * @param whereClause
79.      * @param whereArgs
80.      * @return
81.      */
82. public int
83. int ret = 0;  
84.         SQLiteDatabase database = dbHelper.getWritableDatabase();  
85.         database.beginTransaction();  
86. try
87.             ret = database.update(table, values, whereClause, whereArgs);  
88.             database.setTransactionSuccessful();  
89. catch
90. "update error. ", e);  
91. finally
92.             database.endTransaction();  
93.         }  
94. return
95.     }  
96.   
97. /**
98.      * 数据删除
99.      * @param table
100.      * @param whereClause
101.      * @param whereArgs
102.      * @return
103.      */
104. public int
105.   
106. int ret = 0;  
107.         SQLiteDatabase database = dbHelper.getWritableDatabase();  
108.         database.beginTransaction();  
109. try
110.             ret = database.delete(table, whereClause, whereArgs);  
111.             database.setTransactionSuccessful();  
112. catch
113. "delete error. ", e);  
114. finally
115.             database.endTransaction();  
116.         }  
117. return
118.     }  
119.   
120. }

后面所有的dao都继承该基类,传入泛型就得到了我们想要的,下面给个User的dao例子

[java] 
    view plain 
     copy 
     
  
 
 
1. public class UserRepository extends
2.   
3. public
4. super(context);  
5.     }  
6.   
7. /**
8.      * 插入数据
9.      * @param user
10.      * @return
11.      */
12. public long
13.         ContentValues values = getContentValues(user);  
14. "id");  
15. return insert(DBConstant.TABLE_USER,null,values);  
16.     }  
17.   
18. /**
19.      * 更新数据
20.      * @param user
21.      */
22. public void
23.         ContentValues cv = getContentValues(user);  
24. "id");  
25. "id = ?",new String[]{user.getId()+""});  
26.     }  
27.   
28. /**
29.      * 删除数据
30.      * @param id
31.      */
32. public void delete(int
33. "id = ?",new String[]{id+""});  
34.     }  
35.   
36. /**
37.      * 查询所有数据
38.      * @return
39.      */
40. public
41. null,null, null, null, null, null,null);  
42. if(list != null
43.         {  
44. return
45.         }  
46. return null;  
47.     }  
48.   
49. @Override
50. public
51. new
52.         User user;  
53. while
54. new
55. "id")));  
56. "user_name")));  
57. "user_age")));  
58.             userList.add(user);  
59.         }  
60. return
61.     }  
62.   
63. private
64. new
65. "id",user.getId());  
66. "user_name",user.getUserName());  
67. "user_age",user.getAge());  
68. return
69.     }

 

嗯,看上去简单清爽了很多,需要重写的代码也没有几个,主要还是bean和cursor的转换,对数据库不太了解的朋友可以去查查相关的资料,这里就不做基本知识的普及了。

最后将DBHelper做成单例模式,也贴下代码

[java] 
   view plain 
    copy 
    
 
 
1. public class
2. private static
3. private static
4. private
5.     }  
6.   
7. public static
8. if (instance == null) {  
9. new
10.             initDBHelper(context);  
11.         }  
12. return
13.     }  
14.   
15. private static void
16. new
17.         dbHelper.onCreate(dbHelper.getWritableDatabase());  
18.     }  
19.   
20.   
21. public
22. return
23.     }  
24. }