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

在做一个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 map
Dao<? , ?> dao = lookupDao(tableKey);
if (dao != null) {
@SuppressWarnings("unchecked")
D castDao = (D) dao;
return castDao;
} // now look it up in the class map
Class<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 it
addDaoToTableMap(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; @DatabaseField
private int type; @DatabaseField
private 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 information
DatabaseTable 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语句。

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

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

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. Oozie的详细启动步骤(CDH版本的3节点集群)

    不多说,直接上干货! 我的机器情况是,bigdatamaster(Oozie是安装在这台节点上).bigdataslave1和bigdatalsave2. 启动步骤 第一:先启动mysqld服务进程 ...

  2. TED #04#

    Christopher Ategeka: How adoption worked for me 1. I experienced all the negative effects of poverty ...

  3. Windows Server 2008 R2 web服务器发布在线系统时遇到的问题

    1  HTTP 错误 404.2 - Not Found,由于 Web  服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面(如下图) 打开 Internet 信息服务(IIS) ...

  4. 使用索贝尔(Sobel)进行梯度运算时的数学意义和代码实现研究

    对于做图像处理的工程师来说,Sobel非常熟悉且常用.但是当我们需要使用Sobel进行梯度运算,且希望得到“数学结果”(作为下一步运算的基础)而不是“图片效果”的时候,就必须深入了解Sobel的知识原 ...

  5. Windows10系统远程桌面连接出现卡顿如何解决

    最新的windows10系统下,用户只要开启远程桌面连接,就能够轻松地操控其他电脑.但是,最近部分用户在win10中启用远程连接时,发现电脑窗口变得非常缓慢卡顿,这是怎么回事呢?其实,该问题与系统的设 ...

  6. 使用Xshell连接Ubuntu详解

    Xshell是一个安全终端模拟软件,可以进行远程登录.我使用XShell的主要目的是在Windows环境下登录Linux终端,传输一些大文件到Linux环境上去. 1.下载安装xshell客户端,在安 ...

  7. 扩容swap交换分区空间

    安装linux系统时会指定Swap分区大小,一般是内存的两倍,但在有些场景下可能预先设置的Swap分区空间不足,这个时候需要增加其大小 官方建议在RAM是2到4.5G时,swap是RAM的2倍:如果R ...

  8. ubuntu如何使zsh替换bash

    答:  1.安装zsh sudo apt-get install zsh 2.zsh替换bash sudo chsh -s `which zsh` 3.重启 (注:重启后打开一个终端会自动进入zsh的 ...

  9. git clone时,提示warning: remote HEAD refers to nonexistent ref, unable to checkout

    一.环境 发行版:Ubuntu 18.04.1 LTS 代号:bionic 内核版本:4.15.0-30-generic 二.背景 git clone https://source.codeauror ...

  10. Asynchronous Programming Model (APM)异步编程模型

    https://msdn.microsoft.com/zh-cn/library/ms228963(v=vs.110).aspx 一.概念 An asynchronous operation that ...