OrmLite动态创建表,一个实体类创建多张表的的偏招

来源:互联网 发布:网络曝光是什么意思 编辑:程序博客网 时间:2024/06/07 00:08

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

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

我有一个实体类如下,代表聊天消息,现在要做的是针对每一个当前用户(userId)对应一个朋友(friendId)都要创建一个表。需求比较蛋疼,我本来想的是直接在加两个字段就搞定的,但是我们老大说要分表。没办法只能分表。

public class ChatMessage{public ChatMessage() {}private int _id;private int type;private String content;        /*get and set...*/ }


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

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

这样我们就拿到了Dao对象,就可以进行数据操作了。但是这个方法的对我上面的需求并不管用,因为此方法拿到的数据库表名是固定的tableName="ChatMessage",我现在逍遥的表名肯定是不能固定的,他的格式是tableName="ChatMessage"+userId+friendId。即使在confi里面config.setTableName(tableName) 一样不管用。

查看了OrmLite的源码,发现在DaoManager里面,根据同样的DatabaseTableConfig和类名做了缓存,于是每次拿到的Dao都是同样的Dao

TableConfigConnectionSource tableKey = new TableConfigConnectionSource(connectionSource, tableConfig);// look up in the table mapDao<?, ?> dao = lookupDao(tableKey);if (dao != null) {@SuppressWarnings("unchecked")D castDao = (D) dao;return castDao;}// now look it up in the class mapClass<T> dataClass = tableConfig.getDataClass();ClassConnectionSource classKey = new ClassConnectionSource(connectionSource, dataClass);dao = lookupDao(classKey);if (dao != null) {// if it is not in the table map but is in the class map, add itaddDaoToTableMap(tableKey, dao);@SuppressWarnings("unchecked")D castDao = (D) dao;return castDao;}

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


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

1、首先建个类,如下:

import java.sql.SQLException;import com.j256.ormlite.dao.BaseDaoImpl;import com.j256.ormlite.support.ConnectionSource;import com.j256.ormlite.table.DatabaseTableConfig;import com.roamer.bean.ChatMessage;public class ChatMessageDaoImpl extends BaseDaoImpl<ChatMessage, Integer>{public ChatMessageDaoImpl(ConnectionSource connectionSource, DatabaseTableConfig<ChatMessage> tableConfig) throws SQLException {super(connectionSource, tableConfig);}}

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

DatabaseTable databaseTable = tableConfig.getDataClass().getAnnotation(DatabaseTable.class);if (databaseTable == null || databaseTable.daoClass() == Void.class|| databaseTable.daoClass() == BaseDaoImpl.class) {Dao<T, ?> daoTmp = BaseDaoImpl.createDao(connectionSource, tableConfig);dao = daoTmp;} else {Class<?> daoClass = databaseTable.daoClass();Object[] arguments = new Object[] { connectionSource, tableConfig };Constructor<?> constructor = findConstructor(daoClass, arguments);if (constructor == null) {throw new SQLException("Could not find public constructor with ConnectionSource, DatabaseTableConfig parameters in class "+ daoClass);}try {dao = (Dao<?, ?>) constructor.newInstance(arguments);} catch (Exception e) {throw SqlExceptionUtil.create("Could not call the constructor in class " + daoClass, e);}}

2、ChatMessageDaoImpl指定daoClass

@DatabaseTable(daoClass=ChatMessageDaoImpl.class)public class ChatMessage{public ChatMessage() {}@DatabaseField(generatedId=true)private int _id;@DatabaseFieldprivate int type;@DatabaseFieldprivate String content;/*get and set*/}

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

package com.roamer.db;import java.lang.reflect.Constructor;import java.sql.SQLException;import com.j256.ormlite.dao.BaseDaoImpl;import com.j256.ormlite.dao.Dao;import com.j256.ormlite.misc.SqlExceptionUtil;import com.j256.ormlite.support.ConnectionSource;import com.j256.ormlite.table.DatabaseTable;import com.j256.ormlite.table.DatabaseTableConfig;public class UnlimitDaoManager {public synchronized static <D extends Dao<T, ?>, T> D createDao(ConnectionSource connectionSource,DatabaseTableConfig<T> tableConfig) throws SQLException {if (connectionSource == null) {throw new IllegalArgumentException("connectionSource argument cannot be null");}return doCreateDao(connectionSource, tableConfig);}private static Constructor<?> findConstructor(Class<?> daoClass, Object[] params) {for (Constructor<?> constructor : daoClass.getConstructors()) {Class<?>[] paramsTypes = constructor.getParameterTypes();if (paramsTypes.length == params.length) {boolean match = true;for (int i = 0; i < paramsTypes.length; i++) {if (!paramsTypes[i].isAssignableFrom(params[i].getClass())) {match = false;break;}}if (match) {return constructor;}}}return null;}private static <D extends Dao<T, ?>, T> D doCreateDao(ConnectionSource connectionSource,DatabaseTableConfig<T> tableConfig) throws SQLException {Dao<?, ?> dao = null;// build the DAO using the table informationDatabaseTable databaseTable = tableConfig.getDataClass().getAnnotation(DatabaseTable.class);if (databaseTable == null || databaseTable.daoClass() == Void.class|| databaseTable.daoClass() == BaseDaoImpl.class) {return null;} else {Class<?> daoClass = databaseTable.daoClass();Object[] arguments = new Object[] { connectionSource, tableConfig };Constructor<?> constructor = findConstructor(daoClass, arguments);if (constructor == null) {throw new SQLException("Could not find public constructor with ConnectionSource, DatabaseTableConfig parameters in class "+ daoClass);}try {dao = (Dao<?, ?>) constructor.newInstance(arguments);} catch (Exception e) {throw SqlExceptionUtil.create("Could not call the constructor in class " + daoClass, e);}}@SuppressWarnings("unchecked")D castDao = (D) dao;return castDao;}}

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

package com.roamer.dao;import java.sql.SQLException;import java.util.HashMap;import java.util.List;import java.util.Map;import android.content.Context;import android.database.Cursor;import android.util.Log;import com.j256.ormlite.android.DatabaseTableConfigUtil;import com.j256.ormlite.android.apptools.OpenHelperManager;import com.j256.ormlite.dao.Dao;import com.j256.ormlite.table.DatabaseTableConfig;import com.roamer.bean.ChatMessage;import com.roamer.db.SQLiteHelper;import com.roamer.db.UnlimitDaoManager;public class ChatMessageUtil {private static ChatMessageUtil instance;public static ChatMessageUtil getInstance(Context context) {if (instance == null) {instance = new ChatMessageUtil(context);}return instance;}private SQLiteHelper mHelper;private static final String PREFIX = "message_prefix";public ChatMessageUtil(Context context) {mHelper = OpenHelperManager.getHelper(context, SQLiteHelper.class);}private Map<String, Dao<ChatMessage, Integer>> mDaoMap = new HashMap<String, Dao<ChatMessage, Integer>>();private Dao<ChatMessage, Integer> getDao(String userId, String friendId) {String tableName = PREFIX + userId + friendId;if (mDaoMap.containsKey(tableName)) {return mDaoMap.get(tableName);}Dao<ChatMessage, Integer> dao = null;try {DatabaseTableConfig<ChatMessage> config = DatabaseTableConfigUtil.fromClass(mHelper.getConnectionSource(), ChatMessage.class);config.setTableName(tableName);createTableIfNotExist(tableName);dao = UnlimitDaoManager.createDao(mHelper.getConnectionSource(), config);} catch (SQLException e) {e.printStackTrace();}if (dao != null) {mDaoMap.put(tableName, dao);}return dao;}private void createTableIfNotExist(String tableName) {if (isTableExist(tableName)) {return;}String sql = "CREATE TABLE " + tableName + " (content VARCHAR , _id INTEGER PRIMARY KEY AUTOINCREMENT , type INTEGER )";mHelper.getWritableDatabase().execSQL(sql);Log.d("roamer", "isTableExist(tableName):" + isTableExist(tableName));}private boolean isTableExist(String tableName) {boolean result = false;if (tableName == null) {return false;}Cursor cursor = null;try {String sql = "select count(*) as c from Sqlite_master  where type ='table' and name ='" + tableName.trim() + "' ";cursor = mHelper.getReadableDatabase().rawQuery(sql, null);if (cursor.moveToNext()) {int count = cursor.getInt(0);if (count > 0) {result = true;}}} catch (Exception e) {e.printStackTrace();} finally {if (cursor != null) {cursor.close();}}return result;}public void addMessage(String userId, String friendId, ChatMessage message) {Dao<ChatMessage, Integer> dao = getDao(userId, friendId);try {dao.create(message);} catch (SQLException e) {e.printStackTrace();}}public List<ChatMessage> getAllMessage(String userId, String friendId) {Dao<ChatMessage, Integer> dao = getDao(userId, friendId);try {return dao.queryForAll();} catch (SQLException e) {e.printStackTrace();}return null;}}


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


最后经测试,可以达到我拿蛋疼的需求。

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




2 0
原创粉丝点击