背景
在unity中使用数据库时,
发现发布到webgl的话不能使用sql,报了一堆谷歌不到的错.
不过在提到Sqlite不能使用地方通常都提到了使用另外一个数据库.
LiteDB.
简介
一个使用C#来写的nosql数据库.
特点:
可以像sqlite一样将数据存储到一个文件中
官方做了一些对比,性能比sqlite至少不差
重要的是其改编版本 UltraLiteDB
可以在unity发布到webgl后使用
库文件比较小,不影响游戏体积
为什么换用UltraLiteDB
LiteDB初始化时似乎需要一个本地的文件路径,
如果准备了一个远程的路径,解析发现本地不存在,就会报错
UltraLiteDB体积更加小
UltraLiteDB已经同步到是LiteDB的4.0版本(最新5.0),功能足够
作者在github提供了dll下载
简单使用
这里使用 UltraLiteDB
作为例子.
不过很遗憾作者没有在Readme页面介绍全部的使用方法.
没有模型
类似MongoDB,LiteDB存储使用的BsonDocument类.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 using UltraLiteDB;void DatabaseTest ( ) { var db = new UltraLiteDatabase("MyData.db" ) var col = db.GetCollection("savegames" ); var character = new BsonDocument(); character["Name" ] = "John Doe" ; character["Equipment" ] = new string [] { "sword" , "gnome hat" }; character["Level" ] = 1 ; character["IsActive" ] = true ; BsonValue id = col.Insert(character); character["Name" ] = "Joana Doe" ; col.Update(character); List<BsonDocument> allCharacters = new List<BsonDocument>(characters.FindAll()); col.Delete(10 ); col.Upsert(character); db.Dispose(); }
为了防止忘记使用Dispose,可以使用
1 2 3 4 5 6 void DatabaseTest ( ) { using (var db = new UltraLiteDatabase("MyData.db" )) { var col = db.GetCollection("savegames" ); } }
有模型
但我想大多数人还是需要借助模型的,不然不断使用双引号要疯.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class User { [BsonId ] public int id { get ; set ; } [BsonField("name" ) ] public string name { get ; set ; e} } using (var db = new LiteDatabase("MyData.db" , BsonMapper.Global)) { var users = db.GetCollection<User>("users" ); var user1 = new User() { name = "张三" }; var user2 = new User() { name = "李四" }; users.Insert(new [] { user1, user2 }); user2.name = "王五" ; users.Update(user2); IEnumerable<User> resUsers = users.FindAll(); users.Delete(1 ); }
封装使用
如果想摆脱无处不在的using,也准便摆脱这个文件到底是打开了还是没有的疑问.
一种办法就是搞单例模式.每次使用同一个数据库读写对象.
而在适当的时机销毁这个实例(比如unity某个全局的gameobject的OnDestroy事件中).
首先搞一个单例模式的数据库
1 2 3 4 5 6 7 8 9 10 using UltraLiteDB;static class DB { private static UltraLiteDatabase _instance; public static UltraLiteDatabase GetInstance ( ) { var connectionString = new ConnectionString("MyData.db" ) { }; return _instance ??= new UltraLiteDatabase(connectionString, BsonMapper.Global); } }
然后搞个三行变一行的Helper
原本三行的操作(获取DB,获取集合,做操作),改编成helper的一个方法.
由于目前的个人需要仅仅是读,因此把常用的功能改编一下
FindAll
FindById
Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static class DataHelper { public static IEnumerable <T > FindAll <T >(string tableName ) { UltraLiteDatabase db = DB.GetInstance(); UltraLiteCollection<T> collection = db.GetCollection<T>(tableName); return collection.FindAll(); } public static T FindById <T >(string tableName, int id ) { UltraLiteDatabase db = DB.GetInstance(); UltraLiteCollection<T> collection = db.GetCollection<T>(tableName); return collection.FindById(id); } public static IEnumerable <T > Find <T >(string tableName, Query query ) { UltraLiteDatabase db = DB.GetInstance(); UltraLiteCollection<T> collection = db.GetCollection<T>(tableName); return collection.Find(query); } }
由于封装因人而异,事实上如果不嫌写字符串比较多,现在已经可以结束了
比如使用 DataHelper.FindById<User>("users", 1);
来查询users表的第一条.
但如果还想继续写点,那么可以
为每个Model固定下来表名,泛型的具体值
准备一些常用的查询
留下自定义查询的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using System.Collections.Generic;using Model;using UltraLiteDB;class Users { private static readonly string tableName = "users" ; public static IEnumerable<User> FindAll ( ) { return DataHelper.FindAll<User>(tableName); } public static User FindById (int id ) { return DataHelper.FindById<User>(tableName, id); } public static IEnumerable<Category> WhereType (string type ) { return DataHelper.Find<Category>(tableName, Query.EQ("type" , type)); } public static IEnumerable<User> Find (Query query ) { return DataHelper.Find<User>(tableName, query); } }
到这里,使用起来就有点像 Eloquent
了
1 2 3 4 5 6 7 8 9 10 IEnumerable<User> allUsers = Users.FindAll(); User firstUser = Users.FindById(1 ); IEnumerable<User> someTypeUsers = Users.WhereType("tall" ); User specificUser = Uesr.Find(Query.And( Query.EQ("age" , 20 ), Query.EQ("type" , "smart" )) ).FirstOrDefault();
备注
尽管这里的查询使用的是Query,
但似乎LiteDB官方项目中还可以使用Lambda表达式的方法来写.
如果以后知道了就记录一下.
参考
LiteDB官方
UltraLiteDB官方