绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
LiteDB用法小结
2022-04-15 14:17:48

LiteDB(https://www.litedb.org/)是一种文档型单文件数据库,基于Key-Value方式存取数据。

LiteDB的基本数据结构

BsonDocument

BsonDocument用于存储单一对象,其构造函数接收字典型数据,定义存储的具体内容。

BsonArray

BsonArray用于存储多项同类型对象,其构造函数接收对象集合。

BsonValue

BsonValueBsonDocumentBsonArray的公共基类,可以在运行时确定其具体类型,通过一系列As*方法将其转换为具体类型。

简单对象的存储

对于单一对象,灵活、地控制存储的存取对象数据,是通过自定义对象的序列化和反序列化函数实现。

//
// 自身直接支持LiteDB存储的Point类
//
public readonly struct Point
{
    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public static Point Zero { get; } = new Point(, );

    #region LiteDB
    /// <summary>
    /// 在静态构造函数中调用注册函数,
    /// 确保LiteDB引擎能够找到此类对应的序列化和反序列化函数
    /// </summary>
    static Point() => RegisterType();

    /// <summary>
    /// 注册序列化与反序列化函数
    /// </summary>
    public static void RegisterType()
        => BsonMapper.Global.RegisterType(Serialize, Deserialize);

    /// <summary>
    /// 序列化
    /// </summary>
    public static BsonValue Serialize(Point parameter)
        => new BsonDocument(new Dictionary<string, BsonValue>
        {
            {"X", parameter.X}, // 定义需要存储的数据项
            {"Y", parameter.Y},
        });

    /// <summary>
    /// 反序列化
    /// </summary>
    public static Point Deserialize(BsonValue bsonValue)
    {
        var x = bsonValue["X"].AsDouble; // 提取、解析存储的数据项
        var y = bsonValue["Y"].AsDouble;
        return new Point(x, y);
    }
    #endregion
}

如果存储地对象属于基础类,或者来源于第三方库,为避免因支持LiteDB数据存储带来的“侵入性(invasive)”问题(即为了支持数据持久化儿需要特地修改类的源代码,添加一些与类自身内在逻辑无关的代码),对象的序列化和反序列化函数可以放在类的外部实现,并在必要时,手动注册。

//
// 不直接支持LiteDB存储的Point类
//
public readonly struct Point
{
    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public static Point Zero { get; } = new Point(, );
}
//
// 用于支持Point类存储的工具类
//
public static class PointMapper
{
    /// <summary>
    /// 注册序列化与反序列化函数
    /// </summary>
    public static void RegisterType()
        => BsonMapper.Global.RegisterType(Serialize, Deserialize);

    public static BsonValue Serialize(Point parameter)
        => new BsonDocument(new Dictionary<string, BsonValue>
        {
            {"X", parameter.X},
            {"Y", parameter.Y},
        });

    public static Point Deserialize(BsonValue bsonValue)
    {
        var x = bsonValue["X"].AsDouble;
        var y = bsonValue["Y"].AsDouble;
        return new Point(x, y);
    }
}

集合类的存储

对于需要存储的集合类型的属性,好单独定义一个集合类,然后在这一集合类中自定义如何存储集合中得数据。

通过数组存储集合类数据

public class PointCollection : List<Point>
{
    public PointCollection() { }
    public PointCollection(IEnumerable<Point> points) : base(points) { }

    #region LiteDB
    static PointCollection() => RegisterType();

    public static void RegisterType()
        => BsonMapper.Global.RegisterType(Serialize, Deserialize);

    /// <summary>
    /// 通过BsonArray存储集合元素
    /// 调用Point.Serialize执行Point对象的序列化
    /// </summary>
    public static BsonValue Serialize(PointCollection parameter)
        => new BsonArray(parameter.Select(Point.Serialize)); 

    /// <summary>
    /// 提取BsonArray中存储的集合元素
    /// 调用Point.Deserialize执行Point对象的反序列化
    /// </summary>
    public static PointCollection Deserialize(BsonValue bsonValue)
        => new PointCollection(bsonValue.AsArray.Select(Point.Deserialize));
    #endregion
}

此时LiteDB中存储的数据的格式为

{
  "_id": {"$oid": "6060415bebed2131241a79d6"},
  "Location":  // 单个对象
  {
    "X": 100.0,
    "Y": 200.0
  },
  "Boundary":  // 集合
  [
    {
      "X": 0.0,
      "Y": 0.0
    },
    {
      "X": 12.0,
      "Y": 34.0
    },
    {
      "X": 56.0,
      "Y": 78.0
    }
  ]
}

优化集合类数据的存储

当集合类中的数据项数较多,且元素的数据结构较简单时,可以优化数据的存储,采用更加紧凑的数据结构保存数据,可以提高数据存储的效率。

public class PointCollection : List<Point>
{
    public PointCollection() { }
    public PointCollection(IEnumerable<Point> points) : base(points) { }

    #region LiteDB
    static PointCollection() => RegisterType();

    public static void RegisterType()
        => BsonMapper.Global.RegisterType(Serialize, Deserialize);

    /// <summary>
    /// 将点集合[(X1,Y1),(X2,Y2),(X3,Y3) ...],存储为一维数组[X1,Y1,X2,Y2,X3,Y3 ...]
    /// </summary>
    public static BsonValue Serialize(PointCollection parameter)
        => new BsonArray(parameter.SelectMany(point => new[] {point.X, point.Y})
            .Select(v => new BsonValue(v)));

    /// <summary>
    /// 将一维数组[X1,Y1,X2,Y2,X3,Y3 ...],解析为点集合[(X1,Y1),(X2,Y2),(X3,Y3) ...]
    /// </summary>
    public static PointCollection Deserialize(BsonValue bsonValue)
    {
        var data = bsonValue.AsArray.Select(v => v.AsDouble).ToList();
        Debug.Assert(data.Count % 2 == );
        var points = new List<Point>(data.Count / 2);
        for (var i = ; i < points.Count / 2; i++)
        {
            points.Add(new Point(data[i * 2], data[i * 2 + 1]));
        }

        return new PointCollection(points);
    }
    #endregion
}

此时LiteDB中存储的数据的格式为

{
  "_id": {"$oid": "6060497febed2130105de9db"},
  "Location": 
  {
    "X": 100.0,
    "Y": 200.0
  },
  "Boundary":  // 数据存储更紧凑高效
  [
    0.0,
    0.0,
    12.0,
    34.0,
    56.0,
    78.0
  ]
}

顶层对象的存储

对于顶层对象,LiteDB要求为顶层对象添加一个ID属性。同时,LiteDB在读取顶层对象时,需要指定顶层对象文档集合的名称,这一名称好也由顶层对象类提供。

public class Polygon
{
    public Polygon(Point location, PointCollection boundary)
        : this(ObjectId.NewObjectId(), location, boundary) { }

    /// <summary>
    /// 用于LiteDB反序列化的构造函数
    /// </summary>
    private Polygon(ObjectId id, Point location, PointCollection boundary)
    {
        Id = id;
        Location = location;
        Boundary = boundary;
    }

    public Point Location { get; }
    public PointCollection Boundary { get; }

    /// <summary>
    /// 默认值
    /// </summary>
    public static Polygon Default { get; } = new Polygon(Point.Zero, new PointCollection());

    #region LiteDB
    #region LiteDB顶层对象存储
    /// <summary>
    /// 添加Id属性后,才能作为顶层对象在LiteDB中存储
    /// </summary>
    public ObjectId Id { get; set; }

    /// <summary>
    /// LiteDB顶层对象的文档集合名称
    /// </summary>
    public static string DbCollectionName { get; } = "PolygonData";

    /// <summary>
    /// 添加顶层对象数据
    /// </summary>
    public static void CreateData(LiteDatabase db, Polygon polygon)
    {
        var data = db.GetCollection<Polygon>(DbCollectionName);
        if (data.Count() > )
        {
            data.DeleteAll();
        }

        data.Insert(polygon);
    }

    /// <summary>
    /// 添加顶层对象数据的默认值
    /// </summary>
    public static void CreateDefaultData(LiteDatabase db)
        => CreateData(db, Default);

    /// <summary>
    /// 读取顶层对象数据
    /// </summary>
    public static Polygon GetData(LiteDatabase db)
        => db.GetCollection<Polygon>(DbCollectionName).FindAll().FirstOrDefault();

    /// <summary>
    /// 更新顶层对象数据
    /// </summary>
    public static void UpdateData(LiteDatabase db, Polygon polygon)
        => db.GetCollection<Polygon>(DbCollectionName).Update(polygon);
    #endregion

    #region 序列化与反序列化
    static Polygon() => RegisterType();

    public static void RegisterType()
        => BsonMapper.Global.RegisterType(Serialize, Deserialize);

    public static BsonValue Serialize(Polygon parameter)
        => new BsonDocument(new Dictionary<string, BsonValue>()
        {
            {"_id", parameter.Id},
            {"Location", Point.Serialize(parameter.Location)},
            {"Boundary", PointCollection.Serialize(parameter.Boundary)},
        });

    public static Polygon Deserialize(BsonValue bsonValue)
    {
        Debug.Assert(!bsonValue.IsNull);
        var id = bsonValue["_id"].AsObjectId;
        var location = Point.Deserialize(bsonValue["Location"]);
        var boundary = PointCollection.Deserialize(bsonValue["Boundary"]);
        return new Polygon(id, location, boundary);
    }
    #endregion
    #endregion
}

顶层对象的读写

var dbFilePath = @"D:\testLiteDB2.db";
using (var db = new LiteDatabase(dbFilePath))
{
    Polygon.CreateDefaultData(db); // 创建默认对象
}

using (var db = new LiteDatabase(dbFilePath))
{
    var polygon = Polygon.GetData(db); // 读取对象

    // 修改对象状态
    polygon.Boundary.AddRange(new[]
    {
        new Point(, ),
        new Point(12, 34),
        new Point(56, 78),
    });
    Polygon.UpdateData(db, polygon); // 更新对象
}

LiteDB数据库分析工具

可以通过LiteDB官方网站提供的LiteDB Studio工具查看LiteDB数据库的内容。

https://github.com/mbdavid/LiteDB.Studio

参考资料

分享好友

分享这个小栈给你的朋友们,一起进步吧。

LiteDB
创建时间:2022-04-15 14:15:06
LiteDB
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 飘絮絮絮丶
    专家
戳我,来吐槽~