在 TinyDb 里,ITinyCollection<T> 同时提供同步与异步、单条与批量 API。本文聚焦同步路径,下一篇讲异步。
1. 单条 CRUD 基础范式
using TinyDb.Attributes;
using TinyDb.Bson;
using TinyDb.Core;
[Entity("products")]
public partial class Product
{
[Id]
public ObjectId Id { get; set; } = ObjectId.NewObjectId();
[Index]
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Stock { get; set; }
}
using var db = new TinyDbEngine("crud.db");
var products = db.GetCollection<Product>();
// C
var p = new Product { Name = "机械键盘", Price = 299m, Stock = 100 };
products.Insert(p);
// R
var found = products.FindById(p.Id);
var all = products.FindAll().ToList();
var filtered = products.Find(x => x.Price >= 200m).ToList();
var one = products.FindOne(x => x.Name == "机械键盘");
// U
if (found != null)
{
found.Stock -= 1;
products.Update(found);
}
// D
products.Delete(p.Id);2. 批量插入:优先用 Insert(IEnumerable<T>)
DocumentCollection<T>.Insert(IEnumerable<T>) 内部会分批处理(默认批大小 1000),并走更紧凑的写入路径。
var batch = Enumerable.Range(1, 5000)
.Select(i => new Product
{
Name = $"商品-{i}",
Price = 10 + i % 100,
Stock = 1000 - (i % 200)
})
.ToList();
var inserted = products.Insert(batch);
Console.WriteLine($"批量插入数量: {inserted}");3. 批量更新:先查后改,再整体更新
var needPromote = products.Find(x => x.Stock < 50).ToList();
foreach (var item in needPromote)
{
item.Price *= 0.95m; // 降价促销
}
var updated = products.Update(needPromote);
Console.WriteLine($"批量更新数量: {updated}");4. 批量删除:两种典型方式
方式 A:按条件删
var deletedLowStock = products.DeleteMany(x => x.Stock == 0);
Console.WriteLine($"删除缺货商品: {deletedLowStock}");方式 B:按 ID 列表删
var targetIds = products
.Find(x => x.Price > 500m)
.Take(200)
.Select(x => (BsonValue)x.Id)
.ToList();
var deletedByIds = products.Delete(targetIds);
Console.WriteLine($"按 ID 删除数量: {deletedByIds}");5. Upsert:插入或更新
当你不确定记录是否存在时,用 Upsert 比自己写 FindById + 分支 更简洁。
var candidate = new Product
{
Id = ObjectId.NewObjectId(),
Name = "显示器",
Price = 1299m,
Stock = 30
};
var (type1, count1) = products.Upsert(candidate); // 通常是 Insert
Console.WriteLine($"第一次 Upsert: {type1}, {count1}");
candidate.Stock = 28;
var (type2, count2) = products.Upsert(candidate); // 通常是 Update
Console.WriteLine($"第二次 Upsert: {type2}, {count2}");6. 分页参数建议
Find(predicate, skip, limit) 支持分页,但你应在业务层规范参数:
int page = 1;
int pageSize = 20;
int skip = (page - 1) * pageSize;
var pageData = products.Find(x => x.Price >= 100m, skip, pageSize).ToList();建议约束:
page >= 11 <= pageSize <= 500大页查询优先考虑条件收敛(索引字段)
7. 一段接近生产的仓储封装示例
public sealed class ProductRepository
{
private readonly ITinyCollection<Product> _col;
public ProductRepository(TinyDbEngine db)
{
_col = db.GetCollection<Product>();
}
public ObjectId Add(string name, decimal price, int stock)
{
var p = new Product { Name = name, Price = price, Stock = stock };
_col.Insert(p);
return p.Id;
}
public IReadOnlyList<Product> Search(decimal minPrice, decimal maxPrice, int page, int pageSize)
{
var skip = (page - 1) * pageSize;
return _col.Find(x => x.Price >= minPrice && x.Price <= maxPrice, skip, pageSize).ToList();
}
public bool TryReduceStock(ObjectId id, int quantity)
{
var p = _col.FindById(id);
if (p == null || p.Stock < quantity) return false;
p.Stock -= quantity;
return _col.Update(p) > 0;
}
public int DeleteByIds(IEnumerable<ObjectId> ids)
{
return _col.Delete(ids.Select(x => (BsonValue)x));
}
}8. 结论
日常开发优先:
Insert(IEnumerable)、Update(IEnumerable)、DeleteMany。对“可能存在”记录用
Upsert。大批量操作时,减少每条日志和每条查询,按批次聚合执行。
下一篇进入查询主题:同一份数据如何做过滤、排序、分页、聚合与分组。
发表评论