Perigon.MiniDb 0.0.8

dotnet add package Perigon.MiniDb --version 0.0.8
                    
NuGet\Install-Package Perigon.MiniDb -Version 0.0.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Perigon.MiniDb" Version="0.0.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Perigon.MiniDb" Version="0.0.8" />
                    
Directory.Packages.props
<PackageReference Include="Perigon.MiniDb" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Perigon.MiniDb --version 0.0.8
                    
#r "nuget: Perigon.MiniDb, 0.0.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Perigon.MiniDb@0.0.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Perigon.MiniDb&version=0.0.8
                    
Install as a Cake Addin
#tool nuget:?package=Perigon.MiniDb&version=0.0.8
                    
Install as a Cake Tool

Perigon.MiniDb

一个轻量级、高性能的单文件内存数据库引擎,专为小数据量场景设计(≤50MB)。

NuGet License

✨ 核心特性

  • 🚀 全异步API:完整的 async/await 支持,非阻塞I/O操作
  • 💾 单文件存储:所有数据存储在一个二进制文件中
  • ⚡ 内存操作:全量数据加载到内存,LINQ查询性能极佳
  • 📝 增量更新:只写入修改的记录,避免全量写入
  • 🔒 线程安全:共享内存架构,单线程文件写入队列
  • 🎯 简单API:类似 EF Core 的使用体验,无需复杂配置
  • 🔧 零依赖:完全自包含实现,无需外部库
  • ✅ 类型安全:强类型实体模型,编译时检查

📦 安装

NuGet Package Manager

Install-Package Perigon.MiniDb

.NET CLI

dotnet add package Perigon.MiniDb

PackageReference

<PackageReference Include="Perigon.MiniDb" Version="0.0.1" />

🎯 适用场景

✅ 推荐使用

  • 桌面应用的本地数据存储
  • 开发/测试环境的快速数据库
  • 配置文件的结构化存储
  • 嵌入式应用的轻量级数据库
  • 单用户应用的数据持久化
  • 小型工具和脚本的数据管理

❌ 不推荐使用

  • 多用户Web应用(高并发场景)
  • 大数据集(>50MB文件)
  • 需要复杂查询和索引的场景
  • 需要事务隔离的应用
  • 企业级生产系统

🚀 快速开始

1. 定义实体模型

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Perigon.MiniDb;

public class User : IMicroEntity
{
    public int Id { get; set; }
    
    [MaxLength(50)]  // 必须指定字符串的最大字节数
    public string Name { get; set; } = string.Empty;
    
    [MaxLength(100)]
    public string Email { get; set; } = string.Empty;
    
    public int Age { get; set; }
    public decimal Balance { get; set; }
    public DateTime CreatedAt { get; set; }
    public bool IsActive { get; set; }
    
    // 可空类型支持
    public int? CategoryId { get; set; }
    public DateTime? PublishedAt { get; set; }
    
    // 计算属性 - 不会保存到数据库
    [NotMapped]
    public bool IsAdult => Age >= 18;
    
    // 临时属性 - 不会持久化
    [NotMapped]
    public bool IsProcessing { get; set; }
}
📌 实体模型要求
  1. 必须实现 IMicroEntity 接口:每个实体必须实现 IMicroEntity 接口,该接口定义了 int Id { get; set; } 属性
  2. 字符串必须标注长度:所有 string 类型属性必须使用 [MaxLength] 特性指定最大字节数(UTF-8编码)
  3. 支持 [NotMapped] 特性:使用 [NotMapped] 特性可以排除属性不保存到数据库(计算属性、临时属性等)
  4. 支持的数据类型:仅支持特定类型(见下表)

2. 创建 DbContext

using Perigon.MiniDb;

public class MyDbContext : MiniDbContext
{
    public DbSet<User> Users { get; set; } = null!;
    public DbSet<Product> Products { get; set; } = null!;
}

3. 配置和使用数据库

// 1. 全局配置数据库路径(通常在程序启动时)
MiniDbConfiguration.AddDbContext<MyDbContext>(options => options.UseMiniDb("app.mds"));

// 2. 创建数据库上下文(无需参数)
var db = new MyDbContext();

// 3. 使用数据库
// 初始化:加载数据到内存(自动完成)
await using (db)
{
    // 添加数据
    db.Users.Add(new User 
    { 
        Name = "Alice",
        Email = "alice@example.com",
        Age = 25,
        Balance = 1000m,
        CreatedAt = DateTime.UtcNow,
        IsActive = true
    });
    await db.SaveChangesAsync();

    // 查询数据(支持完整的 LINQ)
    var activeUsers = db.Users
        .Where(u => u.IsActive && u.Balance >= 500)
        .OrderByDescending(u => u.CreatedAt)
        .ToList();

    // 更新数据
    var user = db.Users.First(u => u.Name == "Alice");
    user.Balance += 500m;
    db.Users.Update(user);
    await db.SaveChangesAsync();

    // 删除数据
    db.Users.Remove(user);
    await db.SaveChangesAsync();
}

// 显式释放共享内存缓存(可选,通常在应用退出时调用)
await MiniDbContext.ReleaseSharedCacheAsync("app.mds");

📊 支持的数据类型

类型 大小 说明 示例
int (Id) 4 字节 必需: 实体标识符 public int Id { get; set; } (来自 IMicroEntity)
int 4 字节 32位有符号整数 public int Age { get; set; }
int? 5 字节 可空整数(1字节标记+4字节值) public int? CategoryId { get; set; }
bool 1 字节 布尔值 public bool IsActive { get; set; }
bool? 2 字节 可空布尔(1字节标记+1字节值) public bool? IsPublished { get; set; }
decimal 16 字节 高精度十进制(适合金融计算) public decimal Balance { get; set; }
decimal? 17 字节 可空十进制(1字节标记+16字节值) public decimal? Price { get; set; }
DateTime 8 字节 日期时间(UTC格式,Ticks存储) public DateTime CreatedAt { get; set; }
DateTime? 9 字节 可空日期时间(1字节标记+8字节值) public DateTime? PublishedAt { get; set; }
string 可变 UTF-8编码字符串,必须使用 [MaxLength] [MaxLength(100)] public string Name { get; set; }

🔴 不支持的类型

  • long, short, byte
  • double, float
  • byte[], Stream
  • List<T>, Dictionary<K,V>
  • object, dynamic
  • ❌ 自定义类/结构体

⚠️ 字符串使用注意事项

  1. 必须标注长度[MaxLength] 特性是必需的

    [MaxLength(100)]  // 指定UTF-8编码后的最大字节数
    public string Email { get; set; }
    
  2. UTF-8字节数MaxLength 指定的是字节数,而非字符数

    • ASCII字符:1字节
    • 中文字符:通常3字节
    • 表情符号:通常4字节
  3. 超长自动截断:超出 MaxLength 的字符串会自动截断(在UTF-8字符边界)

  4. 未标注默认值:如果忘记标注,默认使用1024字节

💡 [NotMapped] 特性使用

使用 [NotMapped] 特性可以排除属性不保存到数据库:

using System.ComponentModel.DataAnnotations.Schema;

public class User : IMicroEntity
{
    public int Id { get; set; }
    
    [MaxLength(50)]
    public string Name { get; set; } = string.Empty;
    
    public int Age { get; set; }
    
    // 计算属性 - 不会保存到数据库
    [NotMapped]
    public bool IsAdult => Age >= 18;
    
    // 临时状态 - 不会持久化
    [NotMapped]
    public bool IsSelected { get; set; }
    
    // 格式化显示 - 不会存储
    [NotMapped]
    public string DisplayName => $"{Name} (ID: {Id})";
}

使用场景

  • ✅ 计算属性(只读属性,基于其他属性计算)
  • ✅ 临时状态标记(UI 选中状态、处理标记等)
  • ✅ 格式化显示属性
  • ✅ 业务逻辑辅助属性

🔄 通过 JSON 支持复杂类型

对于不支持的复杂类型(嵌套对象、集合等),可以通过 JSON 序列化存储:

using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;

// 复杂类型定义
public class Address
{
    public string Street { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string ZipCode { get; set; } = string.Empty;
}

public class User : IMicroEntity
{
    public int Id { get; set; }
    
    [MaxLength(50)]
    public string Name { get; set; } = string.Empty;
    
    // 复杂类型属性 - 标记为 [NotMapped]
    [NotMapped]
    public Address? Address
    {
        get
        {
            if (string.IsNullOrEmpty(AddressJsonString))
                return null;
            return JsonSerializer.Deserialize<Address>(AddressJsonString);
        }
        set
        {
            AddressJsonString = value == null 
                ? string.Empty 
                : JsonSerializer.Serialize(value);
        }
    }
    
    // 实际存储的 JSON 字符串
    [MaxLength(500)]
    public string AddressJsonString { get; set; } = string.Empty;
}

// 使用示例
var user = new User
{
    Name = "Alice",
    Address = new Address
    {
        Street = "123 Main St",
        City = "New York",
        Country = "USA",
        ZipCode = "10001"
    }
};

db.Users.Add(user);
await db.SaveChangesAsync();

// 加载后自动反序列化
var loaded = db.Users.First();
Console.WriteLine(loaded.Address.City);  // "New York"

适用场景

  • ✅ 嵌套对象(地址、联系人信息等)
  • ✅ 配置数据(键值对、设置项等)
  • ✅ 元数据(标签、属性列表等)
  • ✅ 动态结构数据

注意事项

  • ⚠️ 不能直接查询 JSON 中的嵌套属性
  • ⚠️ 需要加载到内存后再过滤
  • ⚠️ 建议控制 JSON 大小(< 10KB)

🔧 关键行为说明

自动初始化

// ✅ 创建即可用:构造函数自动加载数据
var db = new MyDbContext("app.mds");
await using (db)
{
    // 直接使用,无需额外初始化
    db.Users.Add(new User 
    { 
        Name = "Alice",
        Email = "alice@example.com",
        Age = 25,
        Balance = 1000m,
        CreatedAt = DateTime.UtcNow,
        IsActive = true
    });
    await db.SaveChangesAsync();
}

自动初始化的工作原理

  • 构造函数:创建上下文、打开/创建数据库文件、加载所有表数据到内存
  • 即用:DbSet 属性在构造函数中已初始化,可以直接使用

注意事项

  1. ✅ 构造函数会同步加载数据(对于小数据库 ≤50MB 很快)
  2. ✅ 多个上下文实例共享内存数据(高效)
  3. ✅ 类似 EF Core 的使用体验,无需额外步骤

共享内存架构

// 同一文件的多个上下文共享内存
var db1 = new MyDbContext("app.mds");
var db2 = new MyDbContext("app.mds");

// db1 和 db2 看到的是同一份内存数据
db1.Users.Add(new User 
{ 
    Name = "Alice",
    Email = "alice@example.com",
    Age = 25,
    Balance = 1000m,
    CreatedAt = DateTime.UtcNow,
    IsActive = true
});
await db1.SaveChangesAsync();

// db2 立即看到变化,无需刷新
Console.WriteLine(db2.Users.Count);  // 输出: 1

显式内存管理

// DbContext 销毁时不会释放共享内存
var db = new MyDbContext("app.mds");
await using (db)
{
    // 使用数据库
} // Dispose 时内存仍保留

// 需要释放内存时显式调用
await MyDbContext.ReleaseSharedCacheAsync("app.mds");

软删除机制

// 删除操作只标记记录为已删除
db.Users.Remove(user);
await db.SaveChangesAsync();  // 只写入1字节的删除标记

// 已删除的记录不会出现在查询结果中
var users = db.Users.ToList();  // 自动过滤已删除记录

// 定期压缩可以回收空间(未来版本)

自动ID分配

var db = new MyDbContext("app.mds");

var user = new User 
{ 
    Name = "Alice",
    Email = "alice@example.com",
    Age = 25,
    Balance = 1000m,
    CreatedAt = DateTime.UtcNow,
    IsActive = true
};  // Id = 0(未设置)

db.Users.Add(user);
await db.SaveChangesAsync();

Console.WriteLine(user.Id);  // 自动分配: 1

// 手动指定ID也可以
var user2 = new User 
{ 
    Id = 100,
    Name = "Bob",
    Email = "bob@example.com",
    Age = 30,
    Balance = 2000m,
    CreatedAt = DateTime.UtcNow,
    IsActive = true
};
db.Users.Add(user2);
await db.SaveChangesAsync();  // 使用指定的ID

📁 文件格式

数据库使用固定长度二进制格式,支持高效的随机访问:

┌─────────────────────────────────────────────┐
│ 文件头 (256字节)                           │
│ - 魔法数: "MDB1"                           │
│ - 版本: 1                                  │
│ - 表数量                                   │
│ - 保留字段                                 │
├─────────────────────────────────────────────┤
│ 表元数据 (每表128字节)                     │
│ - 表名                                     │
│ - 记录数                                   │
│ - 记录大小                                 │
│ - 数据起始偏移                             │
├─────────────────────────────────────────────┤
│ 表数据(固定长度记录)                      │
│ [IsDeleted(1B)][Id(4B)][字段数据...]       │
│ [IsDeleted(1B)][Id(4B)][字段数据...]       │
│ ...                                        │
└─────────────────────────────────────────────┘

性能特性

  • O(1) 记录定位offset = tableStart + (id - 1) × recordSize
  • 增量更新:只写入变更的记录
  • 软删除:删除只需设置1字节标记
  • 预知大小:文件大小在创建时即可计算

⚙️ 高级用法

取消令牌支持

var db = new MyDbContext("app.mds");

using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));

try
{
    await db.SaveChangesAsync(cts.Token);
}
catch (OperationCanceledException)
{
    Console.WriteLine("操作已取消");
}

批量操作

var db = new MyDbContext("app.mds");

// 批量添加
for (int i = 0; i < 1000; i++)
{
    db.Users.Add(new User { Name = $"User{i}", Email = $"user{i}@example.com", Age = 20 + (i % 50), Balance = 100m * i, CreatedAt = DateTime.UtcNow, IsActive = true });
}
await db.SaveChangesAsync();  // 一次性写入所有记录

// 批量更新
var users = db.Users.Where(u => u.IsActive).ToList();
foreach (var user in users)
{
    user.Balance += 100;
    db.Users.Update(user);
}
await db.SaveChangesAsync();  // 一次性写入所有更新

复杂查询

var db = new MyDbContext("app.mds");

// 支持完整的 LINQ
var result = db.Users
    .Where(u => u.Age >= 18 && u.Age <= 60)
    .Where(u => u.Balance > 1000m)
    .OrderByDescending(u => u.Balance)
    .ThenBy(u => u.Name)
    .Select(u => new 
    { 
        u.Name, 
        u.Balance, 
        Category = u.CategoryId ?? 0 
    })
    .Take(10)
    .ToList();

📈 性能指标

操作性能

操作 时间复杂度 典型耗时
查询 O(n) 微秒级(内存)
插入(单条) O(1) ~30ms
插入(批量1000条) O(n) < 100ms
更新 O(1) ~30ms
删除 O(1) ~30ms(软删除)
初始化 O(n) 文件大小决定

性能最佳实践

✅ 推荐模式:批量操作
// 批量添加:收集所有更改,一次保存
for (int i = 0; i < 1000; i++)
{
    db.Users.Add(new User { ... });
}
await db.SaveChangesAsync();  // < 100ms for 1000 records
❌ 避免反模式:高频保存
// 不推荐:每次添加都保存
for (int i = 0; i < 1000; i++)
{
    db.Users.Add(new User { ... });
    await db.SaveChangesAsync();  // 1000 × 30ms = 30秒
}

性能说明

  • 文件I/O是主要瓶颈:每次 SaveChangesAsync 涉及磁盘写入
  • 单次保存延迟:~30ms(文件打开、写入、Flush、关闭)
  • 批量操作优势:1000条记录 < 100ms(一次文件操作)
  • 写入队列串行化:保证数据一致性,但会将并发写入排队

推荐配置

  • 记录数:≤ 100,000
  • 文件大小:≤ 50MB
  • 内存占用:≈ 文件大小
  • 并发读取:无限制
  • 并发写入:串行化(单线程队列)
  • 单次SaveChanges延迟:~30ms
  • 批量操作吞吐量:10,000+ 记录/秒
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.8 90 1/15/2026
0.0.7 81 1/15/2026
0.0.6 87 1/9/2026
0.0.5 92 1/1/2026
0.0.4 90 12/30/2025
0.0.3 91 12/30/2025
0.0.2 84 12/30/2025
0.0.1 90 12/30/2025