最近需要用到Sqlite数据库来做一个游戏的数据存储。网上搜了一下,两种方法,一种是自己dll搭建环境有可能还需要编译之类的,我自己是搭建出来了,不过我没采用。

还有一种就是使用sqlitekit插件,他本身是用c#编写的sqlite封装了一套简单的API,供别人使用,而且也没有那些有的没的环境问题。

一、插件快速介绍

  其实插件使用起来很简单,导入之后,看那几个Demo就可以了。支持全平台,并且支持内存数据库,加密之类等等的特性。这些就不一一介绍了。

核心API如下

  1. void Test( SQLiteDB db, ref string log )
  2. {
  3. SQLiteQuery qr;
  4.  
  5. //
  6. // delete table if exists
  7. //
  8. qr = new SQLiteQuery(db, queryDelete);
  9. qr.Step();
  10. qr.Release(); log += "\nTable deleted.";
  11.  
  12. //
  13. // create table
  14. //
  15. qr = new SQLiteQuery(db, queryCreate);
  16. qr.Step();
  17. qr.Release(); log += "\nTable created.";
  18.  
  19. //
  20. // insert string and blob
  21. //
  22. qr = new SQLiteQuery(db, queryInsert);
  23. qr.Bind(testString);
  24. qr.Bind(testBlob);
  25. qr.Step();
  26. qr.Release(); log += "\nInsert test string and blob.";
  27.  
  28. //
  29. // read strings
  30. //
  31. string testStringFromSelect = "";
  32. qr = new SQLiteQuery(db, querySelect);
  33. while( qr.Step() )
  34. {
  35. testStringFromSelect = qr.GetString("str_field");
  36. if( testStringFromSelect != testString )
  37. {
  38. throw new Exception( "Test string are not equal!" );
  39. }
  40.  
  41. byte[] testBlobFromSelect = qr.GetBlob("blob_field");
  42.  
  43. if( testBlobFromSelect.Length != testBlob.Length )
  44. {
  45. throw new Exception( "Test blobs are not equal!" );
  46. }
  47.  
  48. for (int i = 0; i < testBlobFromSelect.Length; i++)
  49. {
  50. if( testBlobFromSelect[i] != testBlob[i] )
  51. {
  52. throw new Exception( "Test blobs are not equal!" );
  53. }
  54. }
  55. }
  56. if( testStringFromSelect == "" )
  57. {
  58. throw new Exception( "Unknowm problem!" );
  59. }
  60. qr.Release(); log += "\nRead and test strings and blobs.";
  61.  
  62. //
  63. //
  64. // delete table
  65. //
  66. qr = new SQLiteQuery(db, queryDelete);
  67. qr.Step();
  68. qr.Release(); log += "\nTable deleted.";
  69.  
  70. //
  71. // if we reach that point it's mean we pass the test!
  72. db.Close(); log += "\nDatabase closed!\nTest succeeded!";
  73.  
  74. }

二、进一步封装

        尽管上述的API已经很强大了,但是我们还需要再进一步。

     我们经常需要对数据的操作无非就是增删改查,最麻烦是往往就是要根据数据库的表结构生成对应的类在内存中使用,或者内存中的类转化成数据库语言对数据库操作。

这期间往往会造成大量的代码重复。

这里举一个简单的例子

    

  1. public class MyFirstTable
  2. {
  3. public int id;
  4. public string b;
  5. public string c;
  6. }

        如果我们要把表与数据库交互,保守估计就要四条,增删改查

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, 进而操作表的数据。

    这样一来,不仅节省了我们大量的时间,而且这些表都是一来内存中的类的,有时候如果我们需要增加几个字段或者减少几个字段,那么我们就不用在数据库中改完再回到代码中改这些类的结构,我们只需要改一下类的结构,然后新的表就出来了。

     说干就干,时间很晚了,我讲完思路就直接上代码了,太晚了已经。

    

    核心类

    

  1. //主要是类反射出来的字段进行一些处理方便形成数据库语言
  2. public class Column
  3. {
  4. public Type ColumnType;
  5.  
  6. public string TableType
  7. {
  8. get
  9. {
  10. if (IsPrimaryKey)
  11. return "INTEGER PRIMARY KEY";
  12. else
  13. return To_TableType(ColumnType);
  14. }
  15. }
  16.  
  17. //
  18. public bool IsPrimaryKey {
  19. get {
  20. return ColumnName.ToLower().StartsWith("id") && ColumnType == typeof(int);
  21. }
  22. }
  23.  
  24. public string To_TableType(Type type)
  25. {
  26. if (type == typeof(int)) return ColType.INTEGER.ToString();
  27.  
  28. if (type == typeof(string)) return ColType.TEXT.ToString();
  29.  
  30. throw new Exception("Wrong Type");
  31. }
  32.  
  33. public string ColumnName;
  34.  
  35. //Column Value
  36. MyProperty Property;
  37.  
  38. public object ColumnValue
  39. {
  40. get
  41. {
  42. if (Property == null) return null;
  43.  
  44. if (ColumnType == typeof(string))
  45. {
  46. return ((MyProperty<string>)(Property)).GetValue();
  47. }
  48. else if (ColumnType == typeof(String))
  49. {
  50. return ((MyProperty<String>)(Property)).GetValue();
  51. }
  52. else if (ColumnType == typeof(int))
  53. {
  54. return ((MyProperty<int>)(Property)).GetValue();
  55. }
  56. //else if (ColumnType == typeof(Enum))
  57. //{
  58. // return ((MyProperty<int>)(Property)).GetValue();
  59. //}
  60. else
  61. {
  62. return null;
  63. }
  64. }
  65. }
  66.  
  67. public Column(Type ColumnType, string ColumnName, object value)
  68. {
  69. this.ColumnType = ColumnType;
  70.  
  71. this.ColumnName = ColumnName;
  72.  
  73. if (ColumnType == typeof(string))
  74. {
  75. string v = Convert.ToString(value);
  76.  
  77. Property = new MyProperty<string>();
  78. ((MyProperty<string>)(Property)).SetValue(v);
  79. }
  80. else if (ColumnType == typeof(String))
  81. {
  82. String v = Convert.ToString(value);
  83.  
  84. Property = new MyProperty<String>();
  85. ((MyProperty<String>)(Property)).SetValue(v);
  86. }
  87. else if (ColumnType == typeof(int))
  88. {
  89. int v = Convert.ToInt32(value);
  90.  
  91. Property = new MyProperty<int>();
  92. ((MyProperty<int>)(Property)).SetValue(v);
  93. }
  94. //else if (ColumnType == typeof(Enum))
  95. //{
  96. // int v = Convert.ToInt32(value);
  97.  
  98. // Property = new MyProperty<int>();
  99. // ((MyProperty<int>)(Property)).SetValue(v);
  100. //}
  101. else
  102. {
  103. Debuger.LogError("Column Construct Not Right Type :" + ColumnType.ToString());
  104. }
  105.  
  106. }
  107. }
  108.  
  109. public class MyProperty
  110. {
  111. }
  112.  
  113. public class MyProperty<T> : MyProperty
  114. {
  115. public MyProperty()
  116. {
  117. #if UNITY_FLASH
  118. _isValue = false;
  119. #else
  120. _isValue = typeof(T).IsValueType;
  121. #endif
  122. }
  123.  
  124. public bool IsOfType(System.Type t)
  125. {
  126. return t == typeof(T);
  127. }
  128.  
  129. public MyProperty(T value)
  130. : this()
  131. {
  132. _value = value;
  133. }
  134.  
  135. public T GetValue()
  136. {
  137. return _value;
  138. }
  139.  
  140. protected virtual bool IsValueDifferent(T value)
  141. {
  142. return !_value.Equals(value);
  143. }
  144.  
  145. private bool IsClassDifferent(T value)
  146. {
  147. return !_value.Equals(value);
  148. }
  149.  
  150. public virtual void SetValue(T value)
  151. {
  152. if (_changing)
  153. return;
  154. _changing = true;
  155.  
  156. bool changed;
  157.  
  158. if (_isValue)
  159. {
  160. changed = IsValueDifferent(value);
  161. }
  162. else
  163. {
  164. // Value types are handled differently via cached typeof(T).IsValueType checkup
  165. // ReSharper disable CompareNonConstrainedGenericWithNull
  166. changed = (value == null && _value != null) ||
  167. (value != null && _value == null) ||
  168. (_value != null && IsClassDifferent(value));
  169. // ReSharper restore CompareNonConstrainedGenericWithNull
  170. }
  171. if (changed)
  172. {
  173. _value = value;
  174. //OnValueChanged();
  175. }
  176. _changing = false;
  177. }
  178.  
  179. private bool _changing;
  180. private T _value;
  181. private readonly bool _isValue;
  182. }

    

    有了这个核心类,我们就可以直接操作了,还是用之前的那个类,

  1. //数据库字段类型
  2. public enum ColType
  3. {
  4. INTEGER,
  5. TEXT,
  6. REAL,
  7. BLOB
  8. }
  9.  
  10. public class DBUtil<T>
  11. {
  12. public static Column[] GetColumnsByType(T arg)
  13. {
  14. FieldInfo[] fields = arg.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
  15.  
  16. int field_len = fields.Length;
  17.  
  18. if (fields == null || field_len < )
  19. {
  20. return null;
  21. }
  22.  
  23. Column[] tableType = new Column[field_len];
  24. for (int i = ; i < field_len; i++)
  25. {
  26. string Cur_Name = fields[i].Name;
  27.  
  28. Type Cur_Type = fields[i].FieldType;
  29.  
  30. object Value = fields[i].GetValue(arg);
  31.  
  32. tableType[i] = new Column(Cur_Type, Cur_Name, Value);
  33.  
  34. //Debuger.Log("name : " + tableType[i].ColumnName + " type :" + tableType[i].TableType);
  35. }
  36. return tableType;
  37. }
  38.  
  39. public static void CreateTable(ref SQLiteDB db, T arg)
  40. {
  41. SQLiteQuery qr;
  42.  
  43. Type type = arg.GetType();
  44. string TableName = type.Name;
  45.  
  46. string queryDelete = "DROP TABLE IF EXISTS " + TableName + ";";
  47. qr = new SQLiteQuery(db, queryDelete);
  48. qr.Step();
  49. qr.Release();
  50.  
  51. Column[] Columns = GetColumnsByType(arg);
  52. if (Columns == null || Columns.Length < )
  53. {
  54. Debug.LogError("Type is Wrong");
  55. return;
  56. }
  57.  
  58. Debug.Log("NowCreate:" + TableName);
  59. //CREATE TABLE IF NOT EXISTS test_values (id INTEGER PRIMARY KEY, str_field TEXT, blob_field BLOB);
  60. string queryCreate = queryCreateCommond(TableName, Columns);
  61. qr = new SQLiteQuery(db, queryCreate);
  62. qr.Step();
  63. qr.Release();
  64. }
  65. public static string queryCreateCommond(string TableName, Column[] Columns)
  66. {
  67. string queryCreate = "CREATE TABLE IF NOT EXISTS " + TableName + "(" + Columns[].ColumnName + " " + Columns[].TableType;
  68.  
  69. for (var i = ; i < Columns.Length; i++)
  70. {
  71. queryCreate += ", " + Columns[i].ColumnName + " " + Columns[i].TableType;
  72. }
  73. queryCreate += ");";
  74.  
  75. return queryCreate;
  76. }
  77.  
  78. public static void ArrayInsertTable(ref SQLiteDB db, T[] Records)
  79. {
  80.  
  81. for (int i = ; i < Records.Length; i++)
  82. {
  83. InsertTable(ref db, Records[i]);
  84. }
  85. }
  86.  
  87. //注意,主键null自动增加 否则就是要自己控制生成
  88. //自己选择 我这里是自己控制生成的
  89. public static void InsertTable(ref SQLiteDB db, T Record)
  90. {
  91. SQLiteQuery qr;
  92.  
  93. Type type = Record.GetType();
  94. string TableName = type.Name;
  95.  
  96. Column[] Columns = GetColumnsByType(Record);
  97. if (Columns == null || Columns.Length < )
  98. {
  99. Debug.LogError("Type is Wrong");
  100. return;
  101. }
  102.  
  103. Debug.Log("Now Insert:" + TableName);
  104. //"INSERT INTO test_values (str_field,blob_field) VALUES(?,?);";
  105. string queryInsert = queryInsertCommand(TableName, Columns);
  106. qr = new SQLiteQuery(db, queryInsert);
  107. foreach (var item in Columns)
  108. {
  109. //注意,主键null的情况 是可以的 这样一来 就自动增加了 主键
  110. //if (item.IsPrimaryKey)
  111. // qr.BindNull();
  112. //else
  113. qr.Bind(item.ColumnValue.ToString());
  114. }
  115. qr.Step();
  116. qr.Release();
  117. }
  118. public static string queryInsertCommand(string TableName, Column[] column)
  119. {
  120.  
  121. int RowLength = column.Length;
  122.  
  123. string queryInsert = "INSERT INTO " + TableName + "(" + column[].ColumnName;
  124. for (int i = ; i < RowLength; i++)
  125. {
  126. queryInsert += "," + column[i].ColumnName;
  127. }
  128. queryInsert += ") VALUES (?";
  129. for (int i = ; i < RowLength; i++)
  130. {
  131. queryInsert += ",?";
  132. }
  133. queryInsert += ");";
  134.  
  135. return queryInsert;
  136. }
  137.  
  138. //目前 根据Id 索引更新 不够完善
  139. public static void UpdateTableAccordingId(ref SQLiteDB db, T arg)
  140. {
  141. SQLiteQuery qr;
  142.  
  143. Type type = arg.GetType();
  144. string TableName = type.Name;
  145.  
  146. Column[] Columns = GetColumnsByType(arg);
  147. if (Columns == null || Columns.Length < )
  148. {
  149. Debug.LogError("Type is Wrong");
  150. return;
  151. }
  152.  
  153. Column key = null;
  154. Column[] normal = null;
  155. Debug.Log("Now Insert:" + TableName);
  156.  
  157. //"UPDATE MyFirstTable SET b = 'bbbb' ,c = 'bbbb' WHERE id = 1;" 如果使用通配符不用加''
  158. string queryUpdate = queryUpdateCommand(TableName, Columns, ref normal, ref key);
  159. //Debuger.Log(queryUpdate);
  160. qr = new SQLiteQuery(db, queryUpdate);
  161. foreach (var item in normal)
  162. {
  163. qr.Bind(item.ColumnValue.ToString());
  164. }
  165. qr.Bind(key.ColumnValue.ToString());
  166.  
  167. qr.Step();
  168. qr.Release();
  169. }
  170.  
  171. public static string queryUpdateCommand(string TableName, Column[] Columns, ref Column[] normal, ref Column key)
  172. {
  173.  
  174. int RowLength = Columns.Length;
  175.  
  176. normal = GetNormalColumn(Columns);
  177. //"UPDATE test_tbl set b="****",c ="*****" where id=1;"
  178. string queryUpdate = "UPDATE " + TableName + " SET " + normal[].ColumnName + " = ? ";
  179. for (int i = ; i < normal.Length; i++)
  180. {
  181. queryUpdate += "," + normal[i].ColumnName + " = ? ";
  182. }
  183.  
  184. key = GetPrimaryColumn(Columns);
  185. queryUpdate += "WHERE " + key.ColumnName + " = ? ;";
  186.  
  187. return queryUpdate;
  188. }
  189.  
  190. //得到主键字段
  191. static Column GetPrimaryColumn(Column[] Columns)
  192. {
  193. foreach (var item in Columns)
  194. {
  195. if (item.IsPrimaryKey) return item;
  196. }
  197. return null;
  198. }
  199. //普通字段
  200. static Column[] GetNormalColumn(Column[] Columns)
  201. {
  202. List<Column> tmp = new List<Column>();
  203.  
  204. foreach (var item in Columns)
  205. {
  206. if (!item.IsPrimaryKey)
  207. tmp.Add(item);
  208. }
  209. return tmp.ToArray();
  210. }
  211. }

    

     进行一下测ishi 

  1. public class InitDataImport : MonoBehaviour
  2. {
  3.  
  4. public SQLiteDB db;
  5.  
  6. void Start()
  7. {
  8. db = new SQLiteDB();
  9.  
  10. string filename = Application.persistentDataPath + "/" + Global.DataBaseName;
  11.  
  12. //Create DB File Even Not Exits
  13. db.Open(filename);
  14. }
  15.  
  16. void OnDestroy()
  17. {
  18. db.Close();
  19. }
  20.  
  21. void OnGUI()
  22. {
  23. if (GUI.Button(new Rect(10, 10, 100, 70), "Create"))
  24. CreateTab();
  25. if (GUI.Button(new Rect(10, 100, 100, 70), "Insert"))
  26. InsertTab();
  27. if (GUI.Button(new Rect(10, 190, 100, 70), "Update"))
  28. UpdateTab();
  29. if (GUI.Button(new Rect(10, 280, 100, 70), "Select"))
  30. SelectTab();
  31. }
  32.  
  33. public class MyFirstTable
  34. {
  35. public int id;
  36. public string b;
  37. public string c;
  38. }
  39.  
  40. public void CreateTab() {
  41. DBUtil<MyFirstTable>.CreateTable(ref db, new MyFirstTable());
  42. }
  43. public void InsertTab() {
  44.  
  45. for (int i = 0; i < 10; i++)
  46. {
  47. DBUtil<MyFirstTable>.InsertTable(ref db, new MyFirstTable() { id = i, b = "zhangsan", c = "zhejiang" });
  48. }
  49.  
  50. }
  51. public void UpdateTab() {
  52. DBUtil<MyFirstTable>.UpdateTableAccordingId(ref db, new MyFirstTable() { id = 0, b = "lisi", c = "sichuan" });
  53. }
  54. }

  

    上一张图,看结果,很简单,比较简单,不是很完善,主要是看思路

    

    相关需要的插件包 与  软件如下:

    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. 对match() 和 exec() 返回值和属性的测试

    语法: exec() : RegExpObject.exec(string) match() : stringObject.match(string) stringObject.match(regex ...

  2. HDU 1954 Subway tree systems (树的最小表示法)

    题意:用一个字符串表示树,0代表向下走,1代表往回走,求两棵树是否同构. 分析:同构的树经过最小表示会转化成两个相等的串. 方法:递归寻找每一棵子树,将根节点相同的子树的字符串按字典序排列,递归回去即 ...

  3. CSS3属性box-shadow使用教程

    CSS3的box-shadow属性可以让我们轻松实现图层阴影效果.我们来实战详解一下这个属性. 1. box-shadow属性的浏览器兼容性先来看一个这个属性的浏览器兼容性: Opera: 不知道是从 ...

  4. Python线性时间排序——桶排序、基数排序与计数排序

    1. 桶排序 1.1 范围为1-M的桶排序 如果有一个数组A,包含N个整数,值从1到M,我们可以得到一种非常快速的排序,桶排序(bucket sort).留置一个数组S,里面含有M个桶,初始化为0.然 ...

  5. 1102. Invert a Binary Tree (25)

    The following is from Max Howell @twitter: Google: 90% of our engineers use the software you wrote ( ...

  6. PowerPoint Office Mix 插件

    一个内嵌在PowerPoint里的一个教学工具,可以以PPT为核心录制视频. 点下面链接了解并安装 https://mix.office.com/ 首先这货是免费,当然是基于PowerPoint的基础 ...

  7. MinGW-64 安装

    一.在mingw-w64官网下载mingw-w64在线安装包 二.点击mingw-w64进行安装,选择: Version:选最新版本 我这个是4.9.2 Architecture:x86_64 (64 ...

  8. 如何正确理解深度学习(Deep Learning)的概念

    现在深度学习在机器学习领域是一个很热的概念,不过经过各种媒体的转载播报,这个概念也逐渐变得有些神话的感觉:例如,人们可能认为,深度学习是一种能够模拟出人脑的神经结构的机器学习方式,从而能够让计算机具有 ...

  9. SVN四部曲之SVN使用详解进阶

    SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subversion是什么? ...

  10. Mysql 创建数据库表(删除,删除,插入)

    MySQL 创建数据表 创建MySQL数据表需要以下信息: 表名 表字段名 定义每个表字段 语法 以下为创建MySQL数据表的SQL通用语法: CREATE TABLE table_name (col ...