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

在做一个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动态创建表,一个实体类创建多张表的的偏招,布布扣,bubuko.com

时间: 2024-10-26 19:47:25

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

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

首先有几点声明: 1.代码是在别人的基础进行改写的: 2.大家有什么改进的意见可以告诉我,也可以自己改好共享给其他人: 3.刚刚毕业,水平有限,肯定有许多不足之处: 4.希望刚刚学习java的同学能有所启发. //这个是做转换的类,里面的DB只是封装了数据库的连接,大家可以用自己的,随意 package com.tt.util.gen.entity.tool; import java.io.File;import java.io.FileWriter;import java.io.IOExcep

实体类作为另一个实体类的属性

如果一个实体类作为另一个实体类的属性,如果对该属性赋值的时候直接赋一个对象就行了,如果有多个对象同时赋给那个属性 就可以用List集合去接收,就像微信开发里面的图文消息 ,如果回复的是多条图文消息就用list集合去装t它们. 今天早上被技术总监说了一顿,就是他将很多种类都写在一个文件里面,而我一般都是将类写在一个单独的文件里面,我很奇怪这种写法.在QQ群里和人讨论了一下,觉得类应该是单独的建一个文件去写,这样不管是后期维护,还是查阅修改,都会很方便.还有一种所有实体类加partial.需要手动改

复制一张表的数据到另一张表,jq.grid里面有时间类型数据时展示不了数据

1.复制一张表的数据到另一张表 insert into jct_sys_lock_tbl_new  (BGN_DT, END_DT, TYPE, DESCR, flag, format, range, count)  select BGN_DT, END_DT, TYPE, DESCR, flag, format, range, count    from jct_sys_lock_tbl 也可以: insert into jct_sys_lock_tbl_new  select *    fr

佩特来项目经验小集合(3)___从多表统计金额汇总到一张表

来这个项目主要是佩特来公司各部门及各代理商使用的系统,这个系统其中的一下功能就是统计代理商费用.费用的统计放在了费用池(传统方式统计代理商费用就叫费用池)数据表中,代理商可以根据费用池的中的金额购买东西,费用池中的钱来自于代理商每次填写的维修鉴定单中. 下面看一下这部分的数据表结构: 下面的存储过程是汇总材料费及其他费用表的费用并汇总到费用池信息表的存储过程,这段代码有点长,加入了各种判断: -- ============================================= --

java 根据实体类创建映射文件

import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Field; import java.util.List; import java.util.Set; import com.mohe.model.entity.Teach; /** * 根据实体类生成映射文件 * * @author dxm * */ public class Obj

python 第一个Python类(创建类)

'''设计类类名:见名之意,首字母大写,其他遵循驼峰原则属性:见名之意,其他遵循驼峰原则行为(方法/功能):见名之意,其他遵循驼峰原则 类名:Wife属性:sex age height weight faceValue行为:做饭 洗衣服 拖地 揉肩 捶腿 类名:Husband属性:sex age height weight faceValue行为:吃饭 看电视 打游戏 被揉肩 被捶腿 类名:Car属性: color type行为:跑''' '''创建类类:一种数据类型,本身并不占内存空间,根所学

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

1>. 创建一个控制台程序2>. 添加一个 ADO.NET实体数据模型,选择对应的数据库与表(StudentModel.edmx)3>. 控件台代码 static void Main(string[] args) { // 创建一个网关接口,TestData是数据库名 TestDataEntities td = new TestDataEntities(); // 创建一个实体对象,Student是表映射过来的对象,将其赋值 Student st1 = new Student(); st

一个实体类基类实现

为了观察变量方便,我们通常会重写实体类模型的toString方法,可是每一个类都写.有些冗余. 事实上,能够这样子: package others; import java.io.Serializable; import java.lang.reflect.Field; import org.apache.commons.lang3.builder.ToStringBuilder; /** * 重写toString()的实体类基类 * @author limenghua * */ public

读取xml节点值生成一个实体类,读取xml所有节点值,读取所有xml所有节点名称

public partial class WebFormClassByEntity : System.Web.UI.Page    {        List<string> list = new List<string>();//存放所有节点名称        protected void Page_Load(object sender, EventArgs e)        {            //读取xml的文件路径            string filePah