Sqlitekit 封装管理
最近需要用到Sqlite数据库来做一个游戏的数据存储。网上搜了一下,两种方法,一种是自己dll搭建环境有可能还需要编译之类的,我自己是搭建出来了,不过我没采用。
还有一种就是使用sqlitekit插件,他本身是用c#编写的sqlite封装了一套简单的API,供别人使用,而且也没有那些有的没的环境问题。
一、插件快速介绍
其实插件使用起来很简单,导入之后,看那几个Demo就可以了。支持全平台,并且支持内存数据库,加密之类等等的特性。这些就不一一介绍了。
核心API如下
void Test( SQLiteDB db, ref string log )
{
SQLiteQuery qr; //
// delete table if exists
//
qr = new SQLiteQuery(db, queryDelete);
qr.Step();
qr.Release(); log += "\nTable deleted."; //
// create table
//
qr = new SQLiteQuery(db, queryCreate);
qr.Step();
qr.Release(); log += "\nTable created."; //
// insert string and blob
//
qr = new SQLiteQuery(db, queryInsert);
qr.Bind(testString);
qr.Bind(testBlob);
qr.Step();
qr.Release(); log += "\nInsert test string and blob."; //
// read strings
//
string testStringFromSelect = "";
qr = new SQLiteQuery(db, querySelect);
while( qr.Step() )
{
testStringFromSelect = qr.GetString("str_field");
if( testStringFromSelect != testString )
{
throw new Exception( "Test string are not equal!" );
} byte[] testBlobFromSelect = qr.GetBlob("blob_field"); if( testBlobFromSelect.Length != testBlob.Length )
{
throw new Exception( "Test blobs are not equal!" );
} for (int i = 0; i < testBlobFromSelect.Length; i++)
{
if( testBlobFromSelect[i] != testBlob[i] )
{
throw new Exception( "Test blobs are not equal!" );
}
}
}
if( testStringFromSelect == "" )
{
throw new Exception( "Unknowm problem!" );
}
qr.Release(); log += "\nRead and test strings and blobs."; //
//
// delete table
//
qr = new SQLiteQuery(db, queryDelete);
qr.Step();
qr.Release(); log += "\nTable deleted."; //
// if we reach that point it's mean we pass the test!
db.Close(); log += "\nDatabase closed!\nTest succeeded!"; }
二、进一步封装
尽管上述的API已经很强大了,但是我们还需要再进一步。
我们经常需要对数据的操作无非就是增删改查,最麻烦是往往就是要根据数据库的表结构生成对应的类在内存中使用,或者内存中的类转化成数据库语言对数据库操作。
这期间往往会造成大量的代码重复。
这里举一个简单的例子
public class MyFirstTable
{
public int id;
public string b;
public string c;
}
如果我们要把表与数据库交互,保守估计就要四条,增删改查
CREATE TABLE IF NOT EXISTS MyFirstTable (id INTEGER PRIMARY KEY, b TEXT, c TEXT);
INSERT INOT MyFirstTable(id,b,c) VALUS(1,'aa','b');
UPDATE MyFirstTable Set b ='cc',d='dd' WHERE id =1;
……………………………… and so on
这些放在代码中实在是太累述了,如果类一多,写这些就是痛苦的事
这个时候我们可以考虑到了,既然这些语句其实就是那些变量就是内存中的类的变量,我们就在进一步,使用反射来根据类来动态生成数据库语言,从而动态生成Table, 进而操作表的数据。
这样一来,不仅节省了我们大量的时间,而且这些表都是一来内存中的类的,有时候如果我们需要增加几个字段或者减少几个字段,那么我们就不用在数据库中改完再回到代码中改这些类的结构,我们只需要改一下类的结构,然后新的表就出来了。
说干就干,时间很晚了,我讲完思路就直接上代码了,太晚了已经。
核心类
//主要是类反射出来的字段进行一些处理方便形成数据库语言
public class Column
{
public Type ColumnType; public string TableType
{
get
{
if (IsPrimaryKey)
return "INTEGER PRIMARY KEY";
else
return To_TableType(ColumnType);
}
} //
public bool IsPrimaryKey {
get {
return ColumnName.ToLower().StartsWith("id") && ColumnType == typeof(int);
}
} public string To_TableType(Type type)
{
if (type == typeof(int)) return ColType.INTEGER.ToString(); if (type == typeof(string)) return ColType.TEXT.ToString(); throw new Exception("Wrong Type");
} public string ColumnName; //Column Value
MyProperty Property; public object ColumnValue
{
get
{
if (Property == null) return null; if (ColumnType == typeof(string))
{
return ((MyProperty<string>)(Property)).GetValue();
}
else if (ColumnType == typeof(String))
{
return ((MyProperty<String>)(Property)).GetValue();
}
else if (ColumnType == typeof(int))
{
return ((MyProperty<int>)(Property)).GetValue();
}
//else if (ColumnType == typeof(Enum))
//{
// return ((MyProperty<int>)(Property)).GetValue();
//}
else
{
return null;
}
}
} public Column(Type ColumnType, string ColumnName, object value)
{
this.ColumnType = ColumnType; this.ColumnName = ColumnName; if (ColumnType == typeof(string))
{
string v = Convert.ToString(value); Property = new MyProperty<string>();
((MyProperty<string>)(Property)).SetValue(v);
}
else if (ColumnType == typeof(String))
{
String v = Convert.ToString(value); Property = new MyProperty<String>();
((MyProperty<String>)(Property)).SetValue(v);
}
else if (ColumnType == typeof(int))
{
int v = Convert.ToInt32(value); Property = new MyProperty<int>();
((MyProperty<int>)(Property)).SetValue(v);
}
//else if (ColumnType == typeof(Enum))
//{
// int v = Convert.ToInt32(value); // Property = new MyProperty<int>();
// ((MyProperty<int>)(Property)).SetValue(v);
//}
else
{
Debuger.LogError("Column Construct Not Right Type :" + ColumnType.ToString());
} }
} public class MyProperty
{
} public class MyProperty<T> : MyProperty
{
public MyProperty()
{
#if UNITY_FLASH
_isValue = false;
#else
_isValue = typeof(T).IsValueType;
#endif
} public bool IsOfType(System.Type t)
{
return t == typeof(T);
} public MyProperty(T value)
: this()
{
_value = value;
} public T GetValue()
{
return _value;
} protected virtual bool IsValueDifferent(T value)
{
return !_value.Equals(value);
} private bool IsClassDifferent(T value)
{
return !_value.Equals(value);
} public virtual void SetValue(T value)
{
if (_changing)
return;
_changing = true; bool changed; if (_isValue)
{
changed = IsValueDifferent(value);
}
else
{
// Value types are handled differently via cached typeof(T).IsValueType checkup
// ReSharper disable CompareNonConstrainedGenericWithNull
changed = (value == null && _value != null) ||
(value != null && _value == null) ||
(_value != null && IsClassDifferent(value));
// ReSharper restore CompareNonConstrainedGenericWithNull
}
if (changed)
{
_value = value;
//OnValueChanged();
}
_changing = false;
} private bool _changing;
private T _value;
private readonly bool _isValue;
}
有了这个核心类,我们就可以直接操作了,还是用之前的那个类,
//数据库字段类型
public enum ColType
{
INTEGER,
TEXT,
REAL,
BLOB
} public class DBUtil<T>
{
public static Column[] GetColumnsByType(T arg)
{
FieldInfo[] fields = arg.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); int field_len = fields.Length; if (fields == null || field_len < )
{
return null;
} Column[] tableType = new Column[field_len];
for (int i = ; i < field_len; i++)
{
string Cur_Name = fields[i].Name; Type Cur_Type = fields[i].FieldType; object Value = fields[i].GetValue(arg); tableType[i] = new Column(Cur_Type, Cur_Name, Value); //Debuger.Log("name : " + tableType[i].ColumnName + " type :" + tableType[i].TableType);
}
return tableType;
} public static void CreateTable(ref SQLiteDB db, T arg)
{
SQLiteQuery qr; Type type = arg.GetType();
string TableName = type.Name; string queryDelete = "DROP TABLE IF EXISTS " + TableName + ";";
qr = new SQLiteQuery(db, queryDelete);
qr.Step();
qr.Release(); Column[] Columns = GetColumnsByType(arg);
if (Columns == null || Columns.Length < )
{
Debug.LogError("Type is Wrong");
return;
} Debug.Log("NowCreate:" + TableName);
//CREATE TABLE IF NOT EXISTS test_values (id INTEGER PRIMARY KEY, str_field TEXT, blob_field BLOB);
string queryCreate = queryCreateCommond(TableName, Columns);
qr = new SQLiteQuery(db, queryCreate);
qr.Step();
qr.Release();
}
public static string queryCreateCommond(string TableName, Column[] Columns)
{
string queryCreate = "CREATE TABLE IF NOT EXISTS " + TableName + "(" + Columns[].ColumnName + " " + Columns[].TableType; for (var i = ; i < Columns.Length; i++)
{
queryCreate += ", " + Columns[i].ColumnName + " " + Columns[i].TableType;
}
queryCreate += ");"; return queryCreate;
} public static void ArrayInsertTable(ref SQLiteDB db, T[] Records)
{ for (int i = ; i < Records.Length; i++)
{
InsertTable(ref db, Records[i]);
}
} //注意,主键null自动增加 否则就是要自己控制生成
//自己选择 我这里是自己控制生成的
public static void InsertTable(ref SQLiteDB db, T Record)
{
SQLiteQuery qr; Type type = Record.GetType();
string TableName = type.Name; Column[] Columns = GetColumnsByType(Record);
if (Columns == null || Columns.Length < )
{
Debug.LogError("Type is Wrong");
return;
} Debug.Log("Now Insert:" + TableName);
//"INSERT INTO test_values (str_field,blob_field) VALUES(?,?);";
string queryInsert = queryInsertCommand(TableName, Columns);
qr = new SQLiteQuery(db, queryInsert);
foreach (var item in Columns)
{
//注意,主键null的情况 是可以的 这样一来 就自动增加了 主键
//if (item.IsPrimaryKey)
// qr.BindNull();
//else
qr.Bind(item.ColumnValue.ToString());
}
qr.Step();
qr.Release();
}
public static string queryInsertCommand(string TableName, Column[] column)
{ int RowLength = column.Length; string queryInsert = "INSERT INTO " + TableName + "(" + column[].ColumnName;
for (int i = ; i < RowLength; i++)
{
queryInsert += "," + column[i].ColumnName;
}
queryInsert += ") VALUES (?";
for (int i = ; i < RowLength; i++)
{
queryInsert += ",?";
}
queryInsert += ");"; return queryInsert;
} //目前 根据Id 索引更新 不够完善
public static void UpdateTableAccordingId(ref SQLiteDB db, T arg)
{
SQLiteQuery qr; Type type = arg.GetType();
string TableName = type.Name; Column[] Columns = GetColumnsByType(arg);
if (Columns == null || Columns.Length < )
{
Debug.LogError("Type is Wrong");
return;
} Column key = null;
Column[] normal = null;
Debug.Log("Now Insert:" + TableName); //"UPDATE MyFirstTable SET b = 'bbbb' ,c = 'bbbb' WHERE id = 1;" 如果使用通配符不用加''
string queryUpdate = queryUpdateCommand(TableName, Columns, ref normal, ref key);
//Debuger.Log(queryUpdate);
qr = new SQLiteQuery(db, queryUpdate);
foreach (var item in normal)
{
qr.Bind(item.ColumnValue.ToString());
}
qr.Bind(key.ColumnValue.ToString()); qr.Step();
qr.Release();
} public static string queryUpdateCommand(string TableName, Column[] Columns, ref Column[] normal, ref Column key)
{ int RowLength = Columns.Length; normal = GetNormalColumn(Columns);
//"UPDATE test_tbl set b="****",c ="*****" where id=1;"
string queryUpdate = "UPDATE " + TableName + " SET " + normal[].ColumnName + " = ? ";
for (int i = ; i < normal.Length; i++)
{
queryUpdate += "," + normal[i].ColumnName + " = ? ";
} key = GetPrimaryColumn(Columns);
queryUpdate += "WHERE " + key.ColumnName + " = ? ;"; return queryUpdate;
} //得到主键字段
static Column GetPrimaryColumn(Column[] Columns)
{
foreach (var item in Columns)
{
if (item.IsPrimaryKey) return item;
}
return null;
}
//普通字段
static Column[] GetNormalColumn(Column[] Columns)
{
List<Column> tmp = new List<Column>(); foreach (var item in Columns)
{
if (!item.IsPrimaryKey)
tmp.Add(item);
}
return tmp.ToArray();
}
}
进行一下测ishi
public class InitDataImport : MonoBehaviour
{ public SQLiteDB db; void Start()
{
db = new SQLiteDB(); string filename = Application.persistentDataPath + "/" + Global.DataBaseName; //Create DB File Even Not Exits
db.Open(filename);
} void OnDestroy()
{
db.Close();
} void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 100, 70), "Create"))
CreateTab();
if (GUI.Button(new Rect(10, 100, 100, 70), "Insert"))
InsertTab();
if (GUI.Button(new Rect(10, 190, 100, 70), "Update"))
UpdateTab();
if (GUI.Button(new Rect(10, 280, 100, 70), "Select"))
SelectTab();
} public class MyFirstTable
{
public int id;
public string b;
public string c;
} public void CreateTab() {
DBUtil<MyFirstTable>.CreateTable(ref db, new MyFirstTable());
}
public void InsertTab() { for (int i = 0; i < 10; i++)
{
DBUtil<MyFirstTable>.InsertTable(ref db, new MyFirstTable() { id = i, b = "zhangsan", c = "zhejiang" });
} }
public void UpdateTab() {
DBUtil<MyFirstTable>.UpdateTableAccordingId(ref db, new MyFirstTable() { id = 0, b = "lisi", c = "sichuan" });
}
}
上一张图,看结果,很简单,比较简单,不是很完善,主要是看思路
相关需要的插件包 与 软件如下:
http://yunpan.cn/csQp2nP9HwpIH 提取码 2e00
Sqlitekit 封装管理的更多相关文章
- Altium Designer如何批量修改名称,数值,封装
方法一: altium里的封装管理库 1,Tools -> Footprint Manager -> ...2,在Component List里选择要改的器件3,在View and Edi ...
- C#开发微信门户及应用(46)-基于Bootstrap的微信门户应用管理系统功能介绍
在前面介绍很多的微信框架,基本上都采用EasyUI的界面来搭建的微信框架,如随笔<C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍>介绍的一样,不过随着微信的H5应用越来越多,因 ...
- AD软件原理图封装过程(即由原理图转换到PCB)
第一步:先画出你所要的原理图 第二步:点击菜单栏的工具→封装管理器,进去封装管理器页面,点击左边的每一个元件, 然后选择封装时的元器件,再点击右边的确定(每一个元器件确定好封装要用的元件都要点确定) ...
- Altium Designer中如何批量修改元器件封装?
我想你说的应该是altium里的封装管理库吧.1,Tools -> Footprint Manager -> ...2,在Component List里选择要改的器件3,在View and ...
- centos6.5 nginx-1.8.0和ftp搭建图片服务器
一.Nginx的安装步骤 1.Nginx安装环境: gcc: 安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc:yum install gcc-c+ ...
- Tengine 安装配置全过程
Tengine官网上有个非常简单的教程,中间并未涉及到一些常用的设置,所以仅供参考.一下午为本人的安装步骤及过程. 1.安装必要的编译环境好 由于Tengine安装需要使用源代码自行编译,所以在安装前 ...
- 从零开始学 Java - CentOS 下安装 Nginx
早上下起了暴雨 闹钟还未响起就听到雨滴哗啦啦击打窗户的声音,被吵醒了.起床上班,在楼下的十字路口,暴雨大到完全看不清对面,两个穿着雨衣的交警站在路口中间指挥着过往的车辆,大家都慌慌张张.急急忙忙的打着 ...
- 安装Portal for ArcGIS时如何正确配置HTTPS证书
SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持.SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为 ...
- 7. LAMP环境搭建
一.准备工作 1.安装编译工具gcc.gcc-c++ 注意解决依赖关系,推荐使用yum安装,若不能联网可使用安装光盘做为yum源-- 1)编辑yum配置文件: # mount /dev/cdrom / ...
随机推荐
- 关于css的一些小细节---link
<link rel="stylesheet" href=“a.css” type="text/css"> rel:当前文档与被链接文档间的关系,必须 ...
- 在windows下使用linux的开发环境
windows下做开发确实有些不方便,比如python.ruby什么的都要自己装,不过这还是小事情.有一次想安装node-sass,windows下报错缺少MSBuild什么的,可能需要装一个vs解决 ...
- eclipse如何创建web项目
1. 打开eclipse,在File上New,然后选择Dynamic Web Project 2. 弹出的页面中如下图,在Project name中输入项目名称JavaWeb01,点击Next ...
- 《服务器的追踪与审计》RHEL6
在linux系统/etc目录下有两个文件: 服务器的追踪: 当其他人访问我的主机时,通过日志监控到那台主机什么时间通过什么方式登陆,做什么?
- Linux 本地yum源搭建和网络yum源搭建
一.本地yum源搭建 首先挂载上光盘 [root@www /]# mount /dev/cdrom /media/cdrom/ 系统默认已经安装了可使用yum的软件包,所以可以直接配置: [root@ ...
- winform:无法引用其他类库,dll,using等个人看法【图】
在项目类库中已经引用了相关了类库,生成解决方案也没问题,但是到了后置代码,通过using引用其他类库的时候,再生成解决方案或者生成单个类库,就会报“未能找到类型或命名空间“xxx"(是否缺少 ...
- 我开发了一个产品--Markdown Notes
大家好,我开发了一个工具类软件产品--Markdown Notes,中文名是Markdown笔记.想写一篇有关它的文章,目的就是为了推广.推广.推广:) BTW:本文就是用这个工具所写的.
- php获取网页中图片并保存到本地的代码
php获取网页中图片并保存到本地的代码,将网页中图片保存本地文件夹: <?php /** * 获取网页中图片,并保存至本地 * by www.jbxue.com */ header(" ...
- IE下无法保存Cookie和Session问题
最近在做新的Web项目时,因为一个验证码无法保存在Cookie中,或者更确切地说是IE下无法保存Cookie的问题纠结了整整一天时间,考虑了多种原因,单步调试了不下三十次,也没有结果.甚至在无奈之下改 ...
- Boost的自动链接功能
Boost是一个强大的C++第三方库,但是Boost的各种问题实在是很让人蛋疼.我搜到过一篇文章关于LuaBind使用Boost Build管理工具来管理源代码以及编译的博文,其第一句话就是Fuck ...