1. 程式人生 > >OrmLite動態創建表,一個實體類創建多張表的的偏招

OrmLite動態創建表,一個實體類創建多張表的的偏招

call ecs qlite 正式 dsm zed sql base sql語句

版權聲明:本文為博主原創文章。未經博主同意不得轉載。 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動態創建表,一個實體類創建多張表的的偏招