最近需要用到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 封装管理的更多相关文章

  1. Altium Designer如何批量修改名称,数值,封装

    方法一: altium里的封装管理库 1,Tools -> Footprint Manager -> ...2,在Component List里选择要改的器件3,在View and Edi ...

  2. C#开发微信门户及应用(46)-基于Bootstrap的微信门户应用管理系统功能介绍

    在前面介绍很多的微信框架,基本上都采用EasyUI的界面来搭建的微信框架,如随笔<C#开发微信门户及应用(8)-微信门户应用管理系统功能介绍>介绍的一样,不过随着微信的H5应用越来越多,因 ...

  3. AD软件原理图封装过程(即由原理图转换到PCB)

    第一步:先画出你所要的原理图 第二步:点击菜单栏的工具→封装管理器,进去封装管理器页面,点击左边的每一个元件, 然后选择封装时的元器件,再点击右边的确定(每一个元器件确定好封装要用的元件都要点确定) ...

  4. Altium Designer中如何批量修改元器件封装?

    我想你说的应该是altium里的封装管理库吧.1,Tools -> Footprint Manager -> ...2,在Component List里选择要改的器件3,在View and ...

  5. centos6.5 nginx-1.8.0和ftp搭建图片服务器

    一.Nginx的安装步骤 1.Nginx安装环境: gcc: 安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc:yum install gcc-c+ ...

  6. Tengine 安装配置全过程

    Tengine官网上有个非常简单的教程,中间并未涉及到一些常用的设置,所以仅供参考.一下午为本人的安装步骤及过程. 1.安装必要的编译环境好 由于Tengine安装需要使用源代码自行编译,所以在安装前 ...

  7. 从零开始学 Java - CentOS 下安装 Nginx

    早上下起了暴雨 闹钟还未响起就听到雨滴哗啦啦击打窗户的声音,被吵醒了.起床上班,在楼下的十字路口,暴雨大到完全看不清对面,两个穿着雨衣的交警站在路口中间指挥着过往的车辆,大家都慌慌张张.急急忙忙的打着 ...

  8. 安装Portal for ArcGIS时如何正确配置HTTPS证书

    SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持.SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为 ...

  9. 7. LAMP环境搭建

    一.准备工作 1.安装编译工具gcc.gcc-c++ 注意解决依赖关系,推荐使用yum安装,若不能联网可使用安装光盘做为yum源-- 1)编辑yum配置文件: # mount /dev/cdrom / ...

随机推荐

  1. Javascript Class

    做个记录,javascript 如何创建类? 有早期的,有原型的,有构造函数的 // early javascript object var o = {}; o.color = 'red'; o.sh ...

  2. 从0开始学习react(二)

    今天,开始学习第二节!!! 工欲善其事,必先利其器 react推荐我们使用webpack来打包文件,那么我们就用吧!(其实真心不想用啊) 至于好处网上写的天花乱坠的,大家自行解决啊... 这节主要就学 ...

  3. 4月12日学习笔记——jQuery操作属性和样式

    区分 DOM 属性和元素属性 <img src="images/image.1.jpg" id="hibiscus" alt="Hibiscus ...

  4. codeforces Round 286# problem A. Mr. Kitayuta's Gift

    Mr. Kitayuta has kindly given you a string s consisting of lowercase English letters. You are asked ...

  5. nyoj---t448(寻找最大数)

    描述 请在整数 n 中删除m个数字, 使得余下的数字按原次序组成的新数最大, 比如当n=92081346718538,m=10时,则新的最大数是9888   输入 第一行输入一个正整数T,表示有T组测 ...

  6. Codevs 1080 线段树联系

    题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x,加上或 ...

  7. WP开发笔记——阻止Back后退键

    WP7中如何阻止Back后退键的后退事件呢? WP7上提供了物理的Back按键,获取Back物理键按下可以通过PhoneApplicationPage的BackKeyPress事件. 具体实现方法如下 ...

  8. 命名空间 和 class_exist() 问题

    #namespace_test_1.php <?php namespace namespace_test_1; class test { const NAMESPACE = 'namespace ...

  9. WordPress 主题开发 - (一) 前言 待翻译

    原文出自: http://themeshaper.com/2012/10/22/the-themeshaper-wordpress-theme-tutorial-2nd-edition/ THE TH ...

  10. 如何使用js捕获css3动画

    如何使用js捕获css3动画 css3动画功能强大,但是不像js,没有逐帧控制,但是可以通过js事件来确定任何动画的状态. 下面是一段css3动画代码: #anim.enable{ -webkit-a ...