版权声明:本文为博主原创文章。未经博主同意不得转载。 https://blog.csdn.net/LonelyRoamer/article/details/26299355

在做一个Android的项目,由于使用数据库频繁,实体字段也比較多,于是打算採用ORM框架,发现OrmLite还不错,于是下了下来,打算使用。

没想到还没正式开工,就遇到问题了。我如今的一个需求例如以下,

我有一个实体类例如以下。代表聊天消息,如今要做的是针对每个当前用户(userId)相应一个朋友(friendId)都要创建一个表。

需求比較蛋疼,我本来想的是直接在加两个字段就搞定的。可是我们老大说要分表。没办法仅仅能分表。

  1. public class ChatMessage{
  2. public ChatMessage() {
  3. }
  4. private int _id;
  5. private int type;
  6. private String content;
  7. /*get and set...*/
  8.  }

在OrmLite里面创建表和Dao的基本使用方法例如以下:

  1. DatabaseTableConfig<ChatMessage> config = DatabaseTableConfigUtil.fromClass(mHelper.getConnectionSource(), ChatMessage.class);
  2. TableUtils.createTableIfNotExists(mHelper.getConnectionSource(),config);
  3. dao = DaoManager.createDao(mHelper.getConnectionSource(), config);

这样我们就拿到了Dao对象,就能够进行数据操作了。

可是这种方法的对我上面的需求并无论用,由于此方法拿到的数据库表名是固定的tableName="ChatMessage",我如今逍遥的表名肯定是不能固定的,他的格式是tableName="ChatMessage"+userId+friendId。即使在confi里面config.setTableName(tableName) 一样无论用。

查看了OrmLite的源代码,发如今DaoManager里面。依据相同的DatabaseTableConfig和类名做了缓存,于是每次拿到的Dao都是相同的Dao

  1. TableConfigConnectionSource tableKey = new TableConfigConnectionSource(connectionSource, tableConfig);
  2. // look up in the table map
  3. Dao<?
  4. , ?> dao = lookupDao(tableKey);
  5. if (dao != null) {
  6. @SuppressWarnings("unchecked")
  7. D castDao = (D) dao;
  8. return castDao;
  9. }
  10. // now look it up in the class map
  11. Class<T> dataClass = tableConfig.getDataClass();
  12. ClassConnectionSource classKey = new ClassConnectionSource(connectionSource, dataClass);
  13. dao = lookupDao(classKey);
  14. if (dao != null) {
  15. // if it is not in the table map but is in the class map, add it
  16. addDaoToTableMap(tableKey, dao);
  17. @SuppressWarnings("unchecked")
  18. D castDao = (D) dao;
  19. return castDao;
  20. }

相同的TableUtils.createTableIfNotExists一样进行了推断,使得你的相同的实体类不能创建多张表。

OrmLite这样做肯定是为了性能的优化和数据异步操作的安全性,可是这却妨碍了更加方便的使用了。于是研究下。略微使了点偏招,来达到我上面的需求。

1、首先建个类。例如以下:

  1. import java.sql.SQLException;
  2. import com.j256.ormlite.dao.BaseDaoImpl;
  3. import com.j256.ormlite.support.ConnectionSource;
  4. import com.j256.ormlite.table.DatabaseTableConfig;
  5. import com.roamer.bean.ChatMessage;
  6. public class ChatMessageDaoImpl extends BaseDaoImpl<ChatMessage, Integer>{
  7. public ChatMessageDaoImpl(ConnectionSource connectionSource, DatabaseTableConfig<ChatMessage> tableConfig) throws SQLException {
  8. super(connectionSource, tableConfig);
  9. }
  10. }

实现BaseDaoImpl的原因是,查看源代码,发如今DaoManager.createDao中实例化普通Modal,最后实际都是BaseDaoImpl类。

  1. DatabaseTable databaseTable = tableConfig.getDataClass().getAnnotation(DatabaseTable.class);
  2. if (databaseTable == null || databaseTable.daoClass() == Void.class
  3. || databaseTable.daoClass() == BaseDaoImpl.class) {
  4. Dao<T, ?> daoTmp = BaseDaoImpl.createDao(connectionSource, tableConfig);
  5. dao = daoTmp;
  6. } else {
  7. Class<?
  8. > daoClass = databaseTable.daoClass();
  9. Object[] arguments = new Object[] { connectionSource, tableConfig };
  10. Constructor<?> constructor = findConstructor(daoClass, arguments);
  11. if (constructor == null) {
  12. throw new SQLException(
  13. "Could not find public constructor with ConnectionSource, DatabaseTableConfig parameters in class "
  14. + daoClass);
  15. }
  16. try {
  17. dao = (Dao<?
  18. , ?>) constructor.newInstance(arguments);
  19. } catch (Exception e) {
  20. throw SqlExceptionUtil.create("Could not call the constructor in class " + daoClass, e);
  21. }
  22. }

2、ChatMessageDaoImpl指定daoClass

  1. @DatabaseTable(daoClass=ChatMessageDaoImpl.class)
  2. public class ChatMessage{
  3. public ChatMessage() {
  4. }
  5. @DatabaseField(generatedId=true)
  6. private int _id;
  7. @DatabaseField
  8. private int type;
  9. @DatabaseField
  10. private String content;
  11. /*get and set*/
  12. }

3、仿照DaoManager,实现一个不缓存的UnlimitDaoManager

  1. package com.roamer.db;
  2. import java.lang.reflect.Constructor;
  3. import java.sql.SQLException;
  4. import com.j256.ormlite.dao.BaseDaoImpl;
  5. import com.j256.ormlite.dao.Dao;
  6. import com.j256.ormlite.misc.SqlExceptionUtil;
  7. import com.j256.ormlite.support.ConnectionSource;
  8. import com.j256.ormlite.table.DatabaseTable;
  9. import com.j256.ormlite.table.DatabaseTableConfig;
  10. public class UnlimitDaoManager {
  11. public synchronized static <D extends Dao<T, ?>, T> D createDao(ConnectionSource connectionSource,
  12. DatabaseTableConfig<T> tableConfig) throws SQLException {
  13. if (connectionSource == null) {
  14. throw new IllegalArgumentException("connectionSource argument cannot be null");
  15. }
  16. return doCreateDao(connectionSource, tableConfig);
  17. }
  18. private static Constructor<?> findConstructor(Class<?
  19. > daoClass, Object[] params) {
  20. for (Constructor<?
  21. > constructor : daoClass.getConstructors()) {
  22. Class<?>[] paramsTypes = constructor.getParameterTypes();
  23. if (paramsTypes.length == params.length) {
  24. boolean match = true;
  25. for (int i = 0; i < paramsTypes.length; i++) {
  26. if (!paramsTypes[i].isAssignableFrom(params[i].getClass())) {
  27. match = false;
  28. break;
  29. }
  30. }
  31. if (match) {
  32. return constructor;
  33. }
  34. }
  35. }
  36. return null;
  37. }
  38. private static <D extends Dao<T, ?>, T> D doCreateDao(ConnectionSource connectionSource,
  39. DatabaseTableConfig<T> tableConfig) throws SQLException {
  40. Dao<?, ?> dao = null;
  41. // build the DAO using the table information
  42. DatabaseTable databaseTable = tableConfig.getDataClass().getAnnotation(DatabaseTable.class);
  43. if (databaseTable == null || databaseTable.daoClass() == Void.class
  44. || databaseTable.daoClass() == BaseDaoImpl.class) {
  45. return null;
  46. } else {
  47. Class<?
  48. > daoClass = databaseTable.daoClass();
  49. Object[] arguments = new Object[] { connectionSource, tableConfig };
  50. Constructor<?> constructor = findConstructor(daoClass, arguments);
  51. if (constructor == null) {
  52. throw new SQLException(
  53. "Could not find public constructor with ConnectionSource, DatabaseTableConfig parameters in class "
  54. + daoClass);
  55. }
  56. try {
  57. dao = (Dao<?
  58. , ?>) constructor.newInstance(arguments);
  59. } catch (Exception e) {
  60. throw SqlExceptionUtil.create("Could not call the constructor in class " + daoClass, e);
  61. }
  62. }
  63. @SuppressWarnings("unchecked")
  64. D castDao = (D) dao;
  65. return castDao;
  66. }
  67. }

4、由于上面没有使用DaoManager,所以为了性能和安全的考虑。我们还是要主要的实现下面缓存功能。下一个数据库操作的工具类,例如以下:

  1. package com.roamer.dao;
  2. import java.sql.SQLException;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. import android.content.Context;
  7. import android.database.Cursor;
  8. import android.util.Log;
  9. import com.j256.ormlite.android.DatabaseTableConfigUtil;
  10. import com.j256.ormlite.android.apptools.OpenHelperManager;
  11. import com.j256.ormlite.dao.Dao;
  12. import com.j256.ormlite.table.DatabaseTableConfig;
  13. import com.roamer.bean.ChatMessage;
  14. import com.roamer.db.SQLiteHelper;
  15. import com.roamer.db.UnlimitDaoManager;
  16. public class ChatMessageUtil {
  17. private static ChatMessageUtil instance;
  18. public static ChatMessageUtil getInstance(Context context) {
  19. if (instance == null) {
  20. instance = new ChatMessageUtil(context);
  21. }
  22. return instance;
  23. }
  24. private SQLiteHelper mHelper;
  25. private static final String PREFIX = "message_prefix";
  26. public ChatMessageUtil(Context context) {
  27. mHelper = OpenHelperManager.getHelper(context, SQLiteHelper.class);
  28. }
  29. private Map<String, Dao<ChatMessage, Integer>> mDaoMap = new HashMap<String, Dao<ChatMessage, Integer>>();
  30. private Dao<ChatMessage, Integer> getDao(String userId, String friendId) {
  31. String tableName = PREFIX + userId + friendId;
  32. if (mDaoMap.containsKey(tableName)) {
  33. return mDaoMap.get(tableName);
  34. }
  35. Dao<ChatMessage, Integer> dao = null;
  36. try {
  37. DatabaseTableConfig<ChatMessage> config = DatabaseTableConfigUtil.fromClass(mHelper.getConnectionSource(), ChatMessage.class);
  38. config.setTableName(tableName);
  39. createTableIfNotExist(tableName);
  40. dao = UnlimitDaoManager.createDao(mHelper.getConnectionSource(), config);
  41. } catch (SQLException e) {
  42. e.printStackTrace();
  43. }
  44. if (dao != null) {
  45. mDaoMap.put(tableName, dao);
  46. }
  47. return dao;
  48. }
  49. private void createTableIfNotExist(String tableName) {
  50. if (isTableExist(tableName)) {
  51. return;
  52. }
  53. String sql = "CREATE TABLE " + tableName + " (content VARCHAR , _id INTEGER PRIMARY KEY AUTOINCREMENT , type INTEGER )";
  54. mHelper.getWritableDatabase().execSQL(sql);
  55. Log.d("roamer", "isTableExist(tableName):" + isTableExist(tableName));
  56. }
  57. private boolean isTableExist(String tableName) {
  58. boolean result = false;
  59. if (tableName == null) {
  60. return false;
  61. }
  62. Cursor cursor = null;
  63. try {
  64. String sql = "select count(*) as c from Sqlite_master where type ='table' and name ='" + tableName.trim() + "' ";
  65. cursor = mHelper.getReadableDatabase().rawQuery(sql, null);
  66. if (cursor.moveToNext()) {
  67. int count = cursor.getInt(0);
  68. if (count > 0) {
  69. result = true;
  70. }
  71. }
  72. } catch (Exception e) {
  73. e.printStackTrace();
  74. } finally {
  75. if (cursor != null) {
  76. cursor.close();
  77. }
  78. }
  79. return result;
  80. }
  81. public void addMessage(String userId, String friendId, ChatMessage message) {
  82. Dao<ChatMessage, Integer> dao = getDao(userId, friendId);
  83. try {
  84. dao.create(message);
  85. } catch (SQLException e) {
  86. e.printStackTrace();
  87. }
  88. }
  89. public List<ChatMessage> getAllMessage(String userId, String friendId) {
  90. Dao<ChatMessage, Integer> dao = getDao(userId, friendId);
  91. try {
  92. return dao.queryForAll();
  93. } catch (SQLException e) {
  94. e.printStackTrace();
  95. }
  96. return null;
  97. }
  98. }

在这个里面,没有使用TableUtils来创建表。而是使用了原生SQL语句。

最后经測试。能够达到我拿蛋疼的需求。

写这个文章。是看到有人遇到和我相同的需求。不知道怎么解决,需求有点帮助。

OrmLite动态创建表,一个实体类创建多张表的的偏招的更多相关文章

  1. 使用Visual Studio 快速把 Json,Xml 字符串创建为一个实体类

  2. 通过myEclipse创建hibernate的实体类

    今天有个新项目中需要使用到hibernate,刚好数据库表已经创建完毕,就顺便来总结一下通过myEclipse创建hibernate的实体类. 1..在myEclipse中选择MyEclipse Da ...

  3. C# Emit动态代理生成一个实体对象

    /// <summary> /// 使用Emit动态代理收集实体信息 /// </summary> /// <typeparam name="T"&g ...

  4. Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作

    Entity Framework 的小实例:在项目中添加一个实体类,并做插入操作 1>. 创建一个控制台程序2>. 添加一个 ADO.NET实体数据模型,选择对应的数据库与表(Studen ...

  5. 如何通过java反射将数据库表生成实体类?

    首先有几点声明: 1.代码是在别人的基础进行改写的: 2.大家有什么改进的意见可以告诉我,也可以自己改好共享给其他人: 3.刚刚毕业,水平有限,肯定有许多不足之处: 4.希望刚刚学习java的同学能有 ...

  6. sql把一个表数据插入到另一张表

    把一个表数据插入到另一张表 insert into tableB (field1,field2,field3,field4) select field1,field2,field3,'val4' fr ...

  7. hibernate多表查询,结果封装在自己定义的一个实体类当中(在自己定义的类中增加构造函数)

    hibernate的hql查询直接返回java对象时出现问题3 向大家请教一个问题,现在有三张表,表之间没有关联,我需要将三张表里面的所有东西查询出来存储到一个新的对象中,该如何实现,使用hibern ...

  8. [04] 利用注解生成实体类对应的建表sql语句

    1.实现功能 我们已经对注解有了基本的认识,知道了如何自定义注解,如何使用和最基本的处理注解. 本篇主要介绍,如何使用运行时级别的注解,配合反射来自动生成建表的sql语句.如下例: 我们有实体类Stu ...

  9. 阶段3 1.Mybatis_12.Mybatis注解开发_5 mybatis注解建立实体类属性和数据库表中列的对应关系

    创建新项目,一对多 复制刚才关闭的项目的文件 复制到们的新项目里面 复制包的依赖 删减相关代码.只保留这三个查询的方法 模糊查询改成传统的占位符的方式 之前是可以自定义实体类的属性字段,和数据库的字典 ...

随机推荐

  1. 工具推荐. 在线unix, 在线python/perl脚本测试环境

    在线python, perl, javascript, Lisp, Ruby等  http://melpon.org/wandbox/ 正则表达式在线测试工具 http://tools.jb51.ne ...

  2. 居于mtk芯片安卓车机系统具体流程

    一:车机系统框架  MCU 功能  电源控制  Radio 控制(RDS)  按键检测(Panel/Remote/SW)  常见信号检查(倒车/大灯/刹车)  CAN 模块通讯  ARM- ...

  3. Core Java 4

    p272~p273 1.除捕获异常外的另一种异常处理方式:将异常继续传递给方法调用者. 即:在方法首部添加throws说明符号,取代 try catch语句. 对于方法的调用者而言:要么处理异常,要么 ...

  4. Java之网络爬虫WebCollector2.1.2+selenium2.44+phantomjs2.1.1

    Java之网络爬虫WebCollector2.1.2+selenium2.44+phantomjs2.1.1 一.简介 版本匹配: WebCollector2.12 + selenium2.44.0 ...

  5. Git提交撤销

    场景:本地修改代码后,执行commit提交,但此时想撤销该提交. 执行命令: git reflog   查看所有commit历史 git reset --hard commitid     将当前远程 ...

  6. vs显示行号

    1.工具 2.选项 3.文本编辑器 4.C\C++ 5.常规->显示行号

  7. HBase表的备份

    HBase表备份其实就是先将Table导出,再导入两个过程. 导出过程 //hbase org.apache.hadoop.hbase.mapreduce.Driver export 表名 数据文件位 ...

  8. CCleaner如何禁用开机自动启动

    https://forum.piriform.com/topic/42073-ccleaner-starts-on-startup/ 在options-->setting里面选择开机不启动 在O ...

  9. 修改JS文件都需要重启Idea才能生效解决方法

    最近开始使用Idea,有些地方的确比eclipse方便.但是我发现工程每次修改JS或者是JSP页面后,并没有生效,每次修改都需要重启一次Tomcat这样的确不方便.我想Idea肯定有设置的方法,不可能 ...

  10. POJ 1730 Perfect Pth Powers(唯一分解定理)

    http://poj.org/problem?id=1730 题意:给出一个n,a=b^p,求出最大p值. 思路: 首先利用唯一分解定理,把n写成若干个素数相乘的形势.接下来对于每个指数求最大公约数, ...