探索 .NET 9 控制台应用中的 LiteDB 异步 CRUD 操作
本文主要是使用异步方式,体验
litedb
基本的crud
操作。
LiteDB
是一款轻量级、快速且免费的 .NET NoSQL
嵌入式数据库,专为小型本地应用程序设计。它以单一数据文件的形式提供服务,支持文档存储和查询功能,适用于桌面应用、移动应用和小型 Web
应用等场景。
LiteDB
的主要特点包括:
- 无服务器的 NoSQL 文档存储:
LiteDB
是一个嵌入式数据库,无需独立服务器,数据存储在一个单一文件中,类似于SQLite
。 - 简单易用的 API:
LiteDB
提供类似MongoDB
的简单API
,支持LINQ
查询和SQL-like
命令,使得开发者可以轻松上手。 - 线程安全和 ACID 事务支持:LiteDB 支持线程安全操作和完整的
ACID
事务处理,确保数据的一致性和完整性。 - 数据恢复功能:
LiteDB
使用写前日志(WAL
)机制来保证数据恢复能力,即使在写入失败的情况下也能恢复数据。 - 跨平台支持:
LiteDB
可以在Windows、Linux 和 macOS
等多个平台上运行,具有良好的跨平台兼容性。 - 加密存储:
LiteDB
支持使用DES
或AES
加密算法对数据文件进行加密,保障数据的安全性。 - 文件和流数据存储:
LiteDB
支持存储文件和流数据,类似于MongoDB
的GridFS
功能。 - 开源免费:
LiteDB
是一个开源(MIT
)项目,任何人都可以使用和修改其代码,并且完全免费,包括商业用途。
LiteDB
的使用非常简单,可以通过 NuGet
包管理器轻松安装,并且提供了丰富的文档和示例代码帮助开发者快速上手。此外,LiteDB
还提供了一个名为 LiteDB Studio
的图形用户界面工具,方便用户管理和可视化数据库内容。
总之,LiteDB
是一款功能强大、易于使用的 NoSQL
数据库解决方案,适用于多种场景,值得开发者关注和尝试。
使用 .NET CLI
创建一个控制台应用程序,可以按照以下步骤进行:
-
安装
.NET 9 SDK
:首先,确保你已经安装了.NET 9 SDK
。你可以从官方网站下载并安装最新版本的.NET SDK
。 -
创建新的控制台应用程序:使用
dotnet new console
命令创建一个新的控制台应用程序。这个命令会生成一个包含基本结构的项目文件夹。
dotnet new console -n LiteDBExample
- 导航到项目目录:进入刚刚创建的项目目录。
cd LiteDBExample
- 运行应用程序:使用
dotnet run
命令运行应用程序。
dotnet run
基础控制台项目就创建好了,丝滑般体验;
接下来我们使用 litedb
提供的 nuget
包,进行简单的封装,构建出异步操作的 crud
方法 。
- 安装相关
nuget
包:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LiteDB" Version="5.0.21" />
<PackageReference Include="LiteDB.Async" Version="0.1.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
</ItemGroup>
</Project>
- 创建实体类型 :
Person
public class Person
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = default!;
public uint Age { get; set; }
}
- 定义仓储类规范:
IRepository
using LiteDB;
namespace LiteDBExample.Core.Interfaces;
public interface IRepository<TEntity> where TEntity : class
{
Task<BsonValue> AddAsync(TEntity entity);
Task<int> AddRangeAsync(IEnumerable<TEntity> entities);
Task<IEnumerable<TEntity>> GetAllAsync();
Task<TEntity?> GetByIdAsync(object id);
Task<bool> UpdateAsync(TEntity entity);
Task<int> UpdateRangeAsync(IEnumerable<TEntity> entities);
Task<bool> DeleteAsync(object id);
Task<int> DeleteRangeAsync(IEnumerable<object> ids);
}
- 实现
PersonDbContext
using LiteDB;
using LiteDB.Async;
using LiteDBExample.Core.Entities;
namespace LiteDBExample.Data;
public class PersonDbContext(string connectionString) : IDisposable
{
private readonly LiteDatabaseAsync _database = new(connectionString);
public Task<BsonValue> AddAsync(Person person)
{
var collection = _database.GetCollection<Person>("people");
return collection.InsertAsync(person);
}
public Task<int> AddRangeAsync(IEnumerable<Person> persons)
{
var collection = _database.GetCollection<Person>("people");
return collection.InsertAsync(persons);
}
public Task<IEnumerable<Person>> GetAllAsync()
{
var collection = _database.GetCollection<Person>("people");
return collection.FindAllAsync();
}
public Task<Person?> GetByIdAsync(object id)
{
BsonValue bsonId = new(id);
var collection = _database.GetCollection<Person>("people");
return collection.FindByIdAsync(bsonId);
}
public Task<bool> UpdateAsync(Person person)
{
var collection = _database.GetCollection<Person>("people");
return collection.UpdateAsync(person);
}
public Task<int> UpdateRangeAsync(IEnumerable<Person> persons)
{
var collection = _database.GetCollection<Person>("people");
return collection.UpdateAsync(persons);
}
public Task<bool> DeleteAsync(object id)
{
BsonValue bsonId = new(id);
var collection = _database.GetCollection<Person>("people");
return collection.DeleteAsync(bsonId);
}
public Task<int> DeleteRangeAsync(IEnumerable<object> ids)
{
var collection = _database.GetCollection<Person>("people");
return collection.DeleteManyAsync(a => ids.Contains(a.Id));
}
public void Dispose()
{
_database.Dispose();
}
}
- 定义
Person
类仓储:IPersonRepository
using LiteDBExample.Core.Entities;
using LiteDBExample.Core.Interfaces;
namespace LiteDBExample.Repositories;
public interface IPersonRepository : IRepository<Person>
{
}
- 实现
Person
类仓储:PersonRepository
using LiteDB;
using LiteDBExample.Core.Entities;
using LiteDBExample.Data;
namespace LiteDBExample.Repositories;
public class PersonRepository(PersonDbContext context) : IPersonRepository
{
private readonly PersonDbContext _context = context ?? throw new ArgumentNullException(nameof(context));
public Task<BsonValue> AddAsync(Person entity)
{
return _context.AddAsync(entity);
}
public Task<int> AddRangeAsync(IEnumerable<Person> entities)
{
return _context.AddRangeAsync(entities);
}
public Task<IEnumerable<Person>> GetAllAsync()
{
return _context.GetAllAsync();
}
public Task<Person?> GetByIdAsync(object id)
{
return _context.GetByIdAsync(id);
}
public Task<bool> UpdateAsync(Person entity)
{
return _context.UpdateAsync(entity);
}
public Task<int> UpdateRangeAsync(IEnumerable<Person> entities)
{
return _context.UpdateRangeAsync(entities);
}
public Task<bool> DeleteAsync(object id)
{
return _context.DeleteAsync(id);
}
public Task<int> DeleteRangeAsync(IEnumerable<object> ids)
{
return _context.DeleteRangeAsync(ids);
}
}
- 在
Program.cs
中应用IPersonRepository
using LiteDBExample.Core.Entities;
using LiteDBExample.Repositories;
using Microsoft.Extensions.DependencyInjection;
using LiteDBExample.Data;
namespace LiteDBExample;
internal class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello, LiteDB!");
var services = new ServiceCollection();
ConfigureServices(services);
using var serviceProvider = services.BuildServiceProvider();
var personRepository = serviceProvider.GetRequiredService<IPersonRepository>();
// 多个 Person
var newPeople = new List<Person>
{
new Person { Name = "John Kiny", Age = 16 },
new Person { Name = "John Doe", Age = 30 },
new Person { Name = "Jane Smith", Age = 28 },
new Person { Name = "Alice Johnson", Age = 35 }
};
try
{
Console.WriteLine("===> litedb Async Method Test");
{
// 添加单个 Person
var person = new Person { Name = "Alice Array", Age = 32 };
var bsonId = await personRepository.AddAsync(person);
Console.WriteLine($"bsonId={bsonId}");
// 查询单个 Person
var queryPerson = await personRepository.GetByIdAsync(bsonId);
Console.WriteLine($"guid={queryPerson.Id}, {queryPerson.Name} is {queryPerson.Age} years old.");
// 更新单个 Person
person.Age += 1;
person.Name = "Array";
var updateCount = await personRepository.UpdateAsync(person);
Console.WriteLine($"updateCount={updateCount}");
// 删除单个 Person
var deleteCount = await personRepository.DeleteAsync(bsonId);
Console.WriteLine($"deleteCount={deleteCount}");
// 批量添加多个 Person
int addRange = await personRepository.AddRangeAsync(newPeople);
Console.WriteLine($"addRange={addRange}");
// 查询所有 Person
var people = await personRepository.GetAllAsync();
foreach (var p in people)
{
Console.WriteLine($"guid={p.Id}, {p.Name} is {p.Age} years old.");
}
// 批量更新多个 Person
var updatedPeople = people.Select(p => new Person { Id = p.Id, Name = p.Name, Age = p.Age + 1 });
int updateRows = await personRepository.UpdateRangeAsync(updatedPeople);
Console.WriteLine($"updateRows={updateRows}");
// 批量删除多个 Person
var idsToDelete = new List<object>();
foreach (var item in people.Select(p => p.Id))
{
idsToDelete.Add(item);
};
var ids = idsToDelete.AsEnumerable();
int deleteRows = await personRepository.DeleteRangeAsync(ids);
Console.WriteLine($"deleteRows={deleteRows}");
}
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
private static void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IPersonRepository, PersonRepository>();
services.AddScoped<PersonDbContext>(provider => new PersonDbContext("filename=litedb_example.db"));
}
}
- 运行应用:
dotnet run
- 使用
LiteDB.Studio
工具查看litedb
数据;
当批量添加数据的时候,查看数据信息如下:
Grid
查看
Text
查看
从上图中可以看到 litedb_example.db
文件非常轻量,大概 30kb
左右;