解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
|
# CsvDb 使用手册
本文档基于æºç `NewLife.Core/IO/CsvDb.cs` 与其ä¾èµ– `NewLife.Core/IO/CsvFile.cs`,用于说明 `CsvDb<T>`(CSV 文件轻é‡çº§æ•°æ®åº“ï¼‰çš„è®¾è®¡ç›®æ ‡ã€æ•°æ®æ ¼å¼ã€äº‹åŠ¡æ¨¡åž‹ä¸Ž CRUD 用法。
> 关键è¯ï¼šè¿½åР写ã€é«˜æ€§èƒ½é¡ºåºæŸ¥è¯¢ã€è·³è¿‡æŸå行ã€è¡¨å¤´æ˜ å°„ã€äº‹åŠ¡ç¼“å˜ã€å射缓å˜ã€åºåˆ—化属性å。
---
## 1. 概述
`CsvDb<T>` 是一个以 CSV 文件作为æŒä¹…化å˜å‚¨çš„“轻é‡çº§æ•°æ®åº“â€ï¼Œé€‚åˆï¼š
- 大釿•°æ®éœ€è¦ **å¿«é€Ÿè¿½åŠ ï¼ˆAppend)**ï¼›
- éœ€è¦ **é¡ºåºæ‰«æå¼å¿«é€ŸæŸ¥è¯¢**(`Query`);
- 很少修改/åˆ é™¤ï¼ˆä¿®æ”¹/åˆ é™¤æœ¬è´¨æ˜¯â€œå…¨é‡é‡å†™â€ï¼‰ï¼›
- 桌é¢ç«¯åœºæ™¯ï¼ŒSQLite ç‰å…³ç³»åº“å¯èƒ½å› éžæ³•关机导致æŸåï¼›`CsvDb<T>` è¯»å–æ—¶å¯ **跳过æŸå行**,æé«˜å¯æ¢å¤æ€§ã€‚
é‡è¦çº¦æŸï¼š
- **䏿”¯æŒçº¿ç¨‹å®‰å…¨**ï¼šç±»æ³¨é‡Šæ˜Žç¡®è¦æ±‚“务必确ä¿å•线程æ“作â€ã€‚æºç ä¸éƒ¨åˆ†æ–¹æ³•使用 `lock (this)` 防并å‘,但并éžå®Œæ•´å¹¶å‘设计。
---
## 2. æ•°æ®æ–‡ä»¶æ ¼å¼
### 2.1 文件头(Header)
首行是列åï¼Œæ¥æºäºŽå®žä½“ `T` 的公共实例属性:
- 通过åå°„ç¼“å˜ `_properties = typeof(T).GetProperties(...)` 获å–属性;
- 列å使用 `SerialHelper.GetName(PropertyInfo)`ï¼ˆè€Œä¸æ˜¯å±žæ€§åï¼‰ï¼Œä»¥ä¿æŒä¸Žåºåˆ—化å/特性一致。
写文件时:
- 当文件为空(`FileStream.Position == 0`)时写入表头。
è¯»å–æ–‡ä»¶æ—¶ï¼š
- 首行作为 CSV 列åï¼›
- 建立“文件列 -> 属性索引â€çš„æ˜ 射数组 `columnToProperty`,é¿å…æ¯è¡Œéƒ½æŸ¥å—典。
### 2.2 æ•°æ®è¡Œï¼ˆData Rows)
æ¯è¡Œå¯¹åº”一个 `T` 实例。
写入时:
- è‹¥ `T` 实现 `IModel`:按属性å `src[e.Name]` 读å–值;
- å¦åˆ™é€šè¿‡åå°„ `item.GetValue(e)` 读å–属性值。
è¯»å–æ—¶ï¼š
- 创建 `new T()`;
- 对æ¯åˆ—å°è¯•æŒ‰ç›®æ ‡å±žæ€§ç±»åž‹åšåŸºç¡€æ ¡éªŒï¼ˆæ•´æ•°/浮点/日期ç‰ï¼‰ï¼Œæ ¡éªŒå¤±è´¥åˆ™è·³è¿‡è¯¥å—段;
- å°†å—符串 `raw` 转æ¢ä¸ºç›®æ ‡ç±»åž‹ï¼š`raw.ChangeType(pi.PropertyType)`ï¼›
- å†é€šè¿‡ `IModel` 或 `model.SetValue(pi, value)` 赋值。
---
## 3. æ ¸å¿ƒå±žæ€§
### 3.1 `FileName`
- 类型:`String?`
- è¯ä¹‰ï¼šCSV æ•°æ®æ–‡ä»¶è·¯å¾„
ä½¿ç”¨è¦æ±‚:
- 必须设置;未设置调用会抛出 `ArgumentNullException`ï¼ˆè§ `GetFile()`)。
### 3.2 `Encoding`
- 类型:`Encoding`
- 默认:`Encoding.UTF8`
å½±å“:
- 读å–与写入 CSV æ—¶ä¼ é€’ç»™ `CsvFile.Encoding`。
### 3.3 `Comparer`
- 类型:`IEqualityComparer<T>`
- 默认:`EqualityComparer<T>.Default`
用途:
- `Remove(T)` / `Remove(IEnumerable<T>)` / `Find(T)` / `Set(T, ...)` 用它æ¥åˆ¤æ–“实体是å¦ç›¸åŒâ€ã€‚
å¯é€šè¿‡æž„é€ å‡½æ•° `CsvDb(Func<T?, T?, Boolean> comparer)` ä¼ å…¥è‡ªå®šä¹‰æ¯”è¾ƒé€»è¾‘ã€‚
---
## 4. 事务模型(缓å˜å†™ï¼‰
### 4.1 `BeginTransaction()`
- è¡Œä¸ºï¼šæŠŠå½“å‰æ–‡ä»¶å…¨éƒ¨æ•°æ®è¯»å…¥å†…å˜ï¼ˆ`_cache = FindAll().ToList()`)。
- 之åŽçš„ `Add/Remove/Set/Clear/Find/Query` å°†åŸºäºŽç¼“å˜æ“作(é¿å…é¢‘ç¹ I/O)。
### 4.2 `Commit()`
- 行为:把 `_cache` 覆盖写回文件(`Write(_cache, false)`ï¼‰ï¼Œç„¶åŽæ¸…空缓å˜ã€‚
### 4.3 `Rollback()`
- 行为:仅清空缓å˜ï¼Œä¸å†™å›žç£ç›˜ã€‚
### 4.4 Dispose 自动æäº¤
`CsvDb<T>` 继承 `DisposeBase`,其 `Dispose(Boolean)` 覆盖ä¸ä¼šè°ƒç”¨ `Commit()`:
- 若开å¯è¿‡äº‹åС䏔仿œ‰ç¼“å˜ï¼Œé‡Šæ”¾å¯¹è±¡æ—¶ä¼šè‡ªåЍæäº¤ï¼ˆä¿æŒåކå²å…¼å®¹è¡Œä¸ºï¼‰ã€‚
建议:
- 对“批处ç†â€ä¸ºä¸»çš„场景,建议显示调用 `Commit()`,é¿å…异常时误æäº¤ã€‚
---
## 5. 写入/追åŠ
### 5.1 `Write(IEnumerable<T> models, Boolean append)`
è¯ä¹‰ï¼šæ‰¹é‡å†™å…¥ã€‚
关键点:
- 打开文件方å¼ï¼š`FileMode.OpenOrCreate` + `FileAccess.ReadWrite` + `FileShare.ReadWrite`ï¼›
- `append=true` 时移动到文件尾:`fs.Position = fs.Length`;
- 文件为空时写入表头;
- å†™å®ŒåŽæ‰§è¡Œ `fs.SetLength(fs.Position)`:
- 覆盖写(`append=false`)场景:截æ–原文件多余部分;
- è¿½åŠ å†™æ—¶ä¹Ÿä¼šæŠŠé•¿åº¦è®¾ç½®ä¸ºå½“å‰ä½ç½®ï¼ˆé€šå¸¸ç‰ä»·ï¼‰ã€‚
### 5.2 `Add(T model)` / `Add(IEnumerable<T> models)`
- 若已 `BeginTransaction()`ï¼šä»…è¿½åŠ åˆ° `_cache`ï¼›
- å¦åˆ™ï¼šç›´æŽ¥ `Write(..., append:true)`,性能最好。
---
## 6. 查询
### 6.1 `IEnumerable<T> Query(Func<T, Boolean>? predicate, Int32 count = -1)`
è¯ä¹‰ï¼šé¡ºåºæ‰«ææŸ¥è¯¢ï¼ŒæŒ‰éœ€è¿”回。
行为è¦ç‚¹ï¼š
- å¼€å¯äº‹åŠ¡ï¼ˆ`_cache!=null`ï¼‰æ—¶ï¼šä»Žç¼“å˜æžšä¸¾ï¼Œå‘½ä¸åˆ™ `yield return`ï¼›
- 未开å¯äº‹åŠ¡æ—¶ï¼š
- 使用 `CsvFile.ReadLine()` é€è®°å½•读å–ï¼›
- 首æ¡è®°å½•作为表头;
- åŽç»æ¯æ¡è®°å½•æ ¹æ®æ˜ 射填充到新对象。
æŸå行处ç†ï¼š
- 类型转æ¢è¿‡ç¨‹ä¸ä»»ä½•异常会被æ•获并记录(`XTrace.WriteException(ex)`),该行跳过;
- è‹¥ä¸€è¡Œä¸æ²¡æœ‰ä»»ä½•å—æ®µæˆåŠŸåŒ¹é…(`success == 0`),视为æŸå行并跳过。
`count`:
- 默认 `-1` 表示ä¸é™åˆ¶ï¼›
- æ¯ `yield` ä¸€æ¬¡åŽ `--count`,到 0 结æŸã€‚
### 6.2 `T? Find(Func<T, Boolean>? predicate)`
- ç‰ä»·äºŽ `Query(predicate, 1).FirstOrDefault()`。
### 6.3 `IList<T> FindAll()`
- å¼€å¯äº‹åŠ¡æ—¶è¿”å›žç¼“å˜å‰¯æœ¬ `_cache.ToList()`ï¼›
- å¦åˆ™è¯»å–全部。
### 6.4 `Int32 FindCount()`
- éžäº‹åŠ¡åœºæ™¯ï¼šä½¿ç”¨ `StreamReader.ReadLine()` é€è¡Œè®¡æ•°ï¼ˆè·³è¿‡å¤´éƒ¨ï¼‰ã€‚
- 注æ„:这里按物ç†è¡Œè®¡æ•°ï¼Œä¸è€ƒè™‘ CSV 引å·å—段内æ¢è¡Œçš„æƒ…å†µï¼›åœ¨å¸¸è§„è¡¨æ ¼åž‹ CSV ä¸é€šå¸¸å¯æŽ¥å—。
---
## 7. æ›´æ–°ä¸Žåˆ é™¤ï¼ˆå…¨é‡é‡å†™ï¼Œè¾ƒæ…¢ï¼‰
### 7.1 `Remove(Func<T, Boolean> predicate)`
- 若开å¯äº‹åŠ¡ï¼šå¯¹ `_cache` 执行 `RemoveAll`ï¼›
- å¦åˆ™ï¼š
- `FindAll()` 读入全部;
- 过滤掉命ä¸é¡¹ï¼›
- å† `Write(list, false)` 覆盖写回。
### 7.2 `Update(T model)` / `Set(T model)`
- `Update`ï¼šåªæ›´æ–°ï¼Œä¸å˜åœ¨åˆ™è¿”回 `false`ï¼›
- `Set`:å˜åœ¨åˆ™æ›´æ–°ï¼Œä¸å˜åœ¨åˆ™è¿½åР䏀æ¡ã€‚
未开å¯äº‹åŠ¡æ—¶ï¼š
- 读å–全部到内å˜ï¼Œä¿®æ”¹åŽè¦†ç›–写回。
---
## 8. å¼‚æ¥æŸ¥è¯¢ï¼ˆnet5+ / netstandard2.1+)
在 `NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER` 下æä¾›ï¼š
- `IAsyncEnumerable<T> QueryAsync(Func<T, Boolean>? predicate, Int32 count = -1)`
- `Task<IList<T>> FindAllAsync()`
实现è¦ç‚¹ï¼š
- 内部使用 `CsvFile.ReadAllAsync()`;
- å¤´éƒ¨æ˜ å°„é€»è¾‘ä¸ŽåŒæ¥ç‰ˆä¸€è‡´ï¼›
- å‘ç”Ÿå¼‚å¸¸æ—¶åŒæ ·è®°å½•并跳过行。
---
## 9. 最å°ç¤ºä¾‹
### 9.1 定义实体
```csharp
public class User
{
public Int32 Id { get; set; }
public String? Name { get; set; }
public DateTime CreateTime { get; set; }
}
```
### 9.2 è¿½åŠ å†™å…¥
```csharp
using NewLife.IO;
var db = new CsvDb<User>
{
FileName = "./user.csv",
Encoding = Encoding.UTF8,
};
db.Add(new User { Id = 1, Name = "Stone", CreateTime = DateTime.Now });
db.Add(new User { Id = 2, Name = "NewLife", CreateTime = DateTime.Now });
```
### 9.3 查询
```csharp
foreach (var u in db.Query(e => e.Id > 0))
{
Console.WriteLine($"{u.Id} {u.Name}");
}
```
### 9.4 批处ç†äº‹åŠ¡
```csharp
using var db = new CsvDb<User> { FileName = "./user.csv" };
db.BeginTransaction();
db.Add(new User { Id = 3, Name = "Tx" });
db.Remove(e => e.Id == 1);
db.Commit();
```
---
## 10. 注æ„事项与最佳实践
1. **高频写入优先用 `Add`(éžäº‹åŠ¡ï¼‰**ï¼šå®ƒèµ°è¿½åŠ å†™è·¯å¾„ï¼Œé¿å…å…¨é‡é‡å†™ã€‚
2. **修改/åˆ é™¤æ˜¯ä¸€ç§â€œæ‰¹å¤„ç†æ“作â€**:建议 `BeginTransaction()` åŽé›†ä¸å¤„ç†ï¼Œå† `Commit()`。
3. **å•线程使用**:å³ä½¿å†…部有 `lock (this)`,也ä¸å»ºè®®å¤šçº¿ç¨‹å¹¶å‘æ“作åŒä¸€ä¸ªå®žä¾‹ã€‚
4. **表头列å与属性å**:写入使用 `SerialHelper.GetName`ï¼Œè¯»å–æ˜¯æŒ‰åˆ—åæ˜ å°„åˆ°å±žæ€§ï¼›è‹¥ä½ è‡ªå®šä¹‰åˆ—å(åºåˆ—化特性),è¦ç¡®ä¿å†™å…¥/读å–一致。
---
## 11. 相关链接
- 在线文档:`https://newlifex.com/core/csv_db`
- æºç :`NewLife.Core/IO/CsvDb.cs`
- ä¾èµ–:`NewLife.Core/IO/CsvFile.cs`
|