Skip to content

Commit

Permalink
仓库也放一份
Browse files Browse the repository at this point in the history
  • Loading branch information
lidanger committed Apr 20, 2019
1 parent d8032c7 commit 43d8ae0
Show file tree
Hide file tree
Showing 43 changed files with 4,843 additions and 0 deletions.
52 changes: 52 additions & 0 deletions v3/BsonDocument.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
`BsonDocument`类是LiteDB文档的一个实现。`BsonDocument`内部在一个`Dictionary<string, BsonValue>`中存储键值对。


```C#
var customer = new BsonDocument();
customer["_id"] = ObjectId.NewObjectId();
customer["Name"] = "John Doe";
customer["CreateDate"] = DateTime.Now;
customer["Phones"] = new BsonArray { "8000-0000", "9000-000" };
customer["IsActive"] = true;
customer["IsAdmin"] = new BsonValue(true);
customer.Set("Address.Street", "Av. Protasio Alves, 1331");
```

关于文档字段 **keys**:

- Keys 只包含字符,数字或`_``-`
- Keys 是区分大小写的
- 不允许重复键
- LiteDB保持原始键顺序,包括映射的类。仅有的例外是`_id`字段,它会一直是第一个字段。

关于文档字段 **values**:

- Values 可以是任意BSON数据类型: Null, Int32, Int64, Double, String, Embedded Document, Array, Binary, ObjectId, Guid, Boolean, DateTime, MinValue, MaxValue
- 当一个字段被索引,它的值在BSON序列化后必须小于512字节。
- 无索引的值本身没有大小限制,但整个文档BSON序列化限制为1Mb。这个大小包括BSON使用的所有额外字节。
- `_id` 字段不能是: `Null`, `MinValue` or `MaxValue`
- `_id` 是唯一索引字段,因此值必须小于512字节

关于.NET类

- `BsonValue`
- 这个类可以保存任何BSON数据类型,包括null,数组或文档。
- 对所有支持的.NET数据类型有一个隐式构造器
- 值不会变化
- `RawValue` 属性返回内部.NET对象实例
- `BsonArray`
- 支持 `IEnumerable<BsonValue>`
- 每一个数组项可以有不同的BSON类型对象
- `BsonDocument`
- 缺失字段总是返回`BsonValue.Null`
- `Set``Get` 方法可以配合点分表示法(dotted notation)用于访问/创建内部文档

```C#
// 测试BSON值数据类型
if(customer["Name"].IsString) { ... }

// 辅助获取.NET类型
string str = customer["Name"].AsString;
```

要使用其他.NET数据类型,你需要一个自定义`BsonMapper`类。
64 changes: 64 additions & 0 deletions v3/Collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
文档被存储和组织在集合中。`LiteCollection`在LiteDB中是一个管理集合的通用类。每一个集合必须有一个唯一名称:

- 只包含字母,数字和`_`
- 集合名称是 **区分大小写的**
-`_`开头的集合名称被保留,内部使用

全部集合名称加起来被限制在3000个字节以内。如果你有很多集合的话,请使用短名称。如果每一个集合名称使用大约10个字节,在一个单数据库中,你可以拥有~300个集合。

集合在第一个`Insert``EnsureIndex`操作时自动创建。在一个不存在的的集合中运行查询,删除或更新并不会创建集合。

对无模式文档来说,`LiteCollection<T>`是一个通用类,它作为`BsonDocument`可以与`<T>`一起使用。LiteDB在内部会转换`T``BsonDocument`,并且所有操作都使用这个通用文档。

在这个例子中,两个代码片段产生同样的结果。

```C#
// 强类型类
using(var db = new LiteDatabase("mydb.db"))
{
// 获取集合实例
var col = db.GetCollection<Customer>("customer");

// 向集合插入一个文档 - 如果集合不存在,现在创建
col.Insert(new Customer { Id = 1, Name = "John Doe" });

// 如果Name字段不存在索引,在Name字段上创建新索引
col.EnsureIndex(x => x.Name);

// 现在,搜索你想要的文档
var customer = col.FindOne(x => x.Name == "john doe");
}

// 通用 BsonDocument
using(var db = new LiteDatabase("mydb.db"))
{
// 获取集合实例
var col = db.GetCollection("customer");

// 向集合插入一个文件 - 如果集合不存在,现在创建
col.Insert(new BsonDocument().Add("_id", 1).Add("Name", "John Doe"));

// 如果Name字段不存在索引,在Name字段上创建新索引
col.EnsureIndex("Name");

// 现在,搜索你想要的文档
var customer = col.FindOne(Query.EQ("Name", "john doe"));
}
```
### LiteDatabase API 实例方法

- **`GetCollection<T>`** - 这个方法返回`LiteCollection`的一个实例。如果省略`<T>``<T>``BsonDocument`。这是仅有的获取一个集合实例的方式。
- **`RenameCollection`** - 仅重命名一个集合名称 - 不改变任何文档
- **`CollectionExists`** - 检查一个集合是否已经存在于数据库中
- **`GetCollectionNames`** - 获取数据库中的所有集合名称
- **`DropCollection`** - 删除数据库上的所有文档,所有索引和集合引用

### LiteCollection API 实例方法

- **`Insert`** - 插入一个新文档或一个文档`IEnumberable`。如果你的文档没有`_id`字段,Insert操作会使用`ObjectId`创建一个新的。如果你有一个映射过的对象,可以使用 `AutoId`。参考 [Object Mapping](Object-Mapping)
- **`InsertBulk`** - 用于插入大量文档。将文档分批次,每一批控制一次事务。这个方法每批插入后会清理缓存以保持内存使用率。
- **`Update`** - 更新按`_id`字段标识的文档。如果没找到,返回false
- **`Delete`** - 按`_id`或一个`Query`删除文档。如果没找到,返回false
- **`Find`** - 使用LiteDB查询查找文档。参考 [Query](Query)
- **`EnsureIndex`** - 在一个字段上创建新索引。参考 [Indexes](Indexes)
- **`DropIndex`** - 删除一个存在的索引
19 changes: 19 additions & 0 deletions v3/Connection-String.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
LiteDatabase可以使用一个连接字符串初始化,语法为`key1=value1; key2=value2; ...`。如果你的连接字符串中没有`;`,LiteDB假定你的连接字符串是Filename键。键不分大小写。

### 选项

- **`Filename`** (string): 从DLL目录起始的完整路径或相对路径。
- **`Journal`** (bool): 启用或禁用浮点写检查来确保持久性(默认: true)
- **`Password`** (string): 使用一个密码加密(使用AES)你的数据文件(默认: null - 未加密)
- **`Cache Size`** (int): 缓存页面的最大数量。超过这个大小,会将数据存在磁盘中以防止使用过多内存(默认: 5000)
- **`Timeout`** (TimeSpan): 等待解锁操作的超时时间(线程锁或锁定文件)
- **`Mode`** (Exclusive|ReadOnly|Shared): 怎样打开数据文件(默认: NET35,`Shared`,NetStandard,`Exclusive`)
- **`Initial Size`** (string|long): 如果数据库是新的,分配初始空间大小 - 支持 KB, MB, GB (默认: null)
- **`Limit Size`** (string|long): 数据文件的大小限制 - 支持 KB, MB, GB (默认: null)
- **`Upgrade`** (bool): 如果为true,尝试从旧版本(v2)升级数据文件(默认: null)
- **`Log`** (byte): 数据库调试信息 - 使用`LiteDatabase.Log` (默认: Logger.NONE)
- **`Async`** (bool): 支持"sync over async" 文件流创建,以便在UWP中用来访问任何磁盘文件夹(只用于NetStandard, 默认: false)




100 changes: 100 additions & 0 deletions v3/Data-Structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
LiteDB按文档方式存储数据,这种文档是JSON风格的键值对。文档是无模式的数据结构。每一个文档同时包含你的数据和结构。

```JS
{
_id: 1,
name: { first: "John", last: "Doe" },
age: 37,
salary: 3456.0,
createdDate: { $date: "2014-10-30T00:00:00.00Z" },
phones: ["8000-0000", "9000-0000"]
}
```

- `_id` 包含文档主键 - 集合中的一个唯一值
- `name` 包含一个嵌入文档,有`first``last`两个字段
- `age` 包含一个`Int32`
- `salary` 包含一个`Double`
- `createDate` 包含一个`DateTime`
- `phones` 包含一个`String`数组

LiteDB在集合中存储文档。一个集合是一组相关的文档,它们有一组共享的索引。集合类似于关系数据库的一个表。

### BSON

LiteDB使用BSON(二进制JSON)数据格式存储文档。BSON是包含有额外类型信息的一个JSON二进制表示法。在文档中,字段值可以是任意BSON数据类型,包括其他的文档,数组和文档数组。BSON是一种简单、快速地将文档序列化为二进制的方式。

LiteDB使用[BSON 数据类型](http://bsonspec.org/spec.html)的一个子集。如下为所有支持的LiteDB BSON数据类型和.NET对应关系。

|BSON 类型 |.NET 类型                                                   |
|----------|------------------------------------------------------------|
|MinValue |- |
|Null |Any .NET object with `null` value |
|Int32 |`System.Int32` |
|Int64 |`System.Int64` |
|Double |`System.Double` |
|Decimal |`System.Decimal` |
|String |`System.String` |
|Document |`System.Collection.Generic.Dictionary<string, BsonValue>` |
|Array |`System.Collection.Generic.List<BsonValue>` |
|Binary |`System.Byte[]` |
|ObjectId |`LiteDB.ObjectId` |
|Guid |`System.Guid` |
|Boolean |`System.Boolean` |
|DateTime |`System.DateTime` |
|MaxValue |- |

### 扩展 JSON

要序列化一个文档为JSON,LiteDB使用一个扩展版本的JSON,这样不会丢失任何不存在于JSON中的BSON类型信息。扩展数据类型被表示为一个嵌入文档,用`$`作为初始键,并且值是字符串。

|BSON 数据类型 |JSON 表示法 |描述 |
|--------------|------------------------------------------------------|-----------------------------------|
|ObjectId |`{ "$oid": "507f1f55bcf96cd799438110" }` |12 bytes in hex format |
|Date |`{ "$date": "2015-01-01T00:00:00Z" }` |UTC and ISO-8601 format |
|Guid |`{ "$guid": "ebe8f677-9f27-4303-8699-5081651beb11" }` | |
|Binary |`{ "$binary": "VHlwZSgaFc3sdcGFzUpcmUuLi4=" }` |Byte array in base64 string format |
|Int64 |`{ "$numberLong": "12200000" }` | |
|Decimal |`{ "$numberDecimal": "122.9991" }` | |
|MinValue |`{ "$minValue": "1" }` | |
|MaxValue |`{ "$maxValue": "1" }` | |

LiteDB在它的`JsonSerializer`静态类中实现JSON。序列化和反序列化只接受`BsonValue`作为输入/输出。如果你想转换你的对象类型为一个BsonValue,你需要使用一个`BsonMapper`

```C#
var customer = new Customer { Id = 1, Name = "John Doe" };

var doc = BsonMapper.Global.ToDocument(customer);

var jsonString = JsonSerialize.Serialize(doc, pretty, includeBinaryData);
```

`JsonSerialize`也支持`TextReader``TextWriter`从一个文件或`Stream`中直接读/写。

### ObjectId

`ObjectId`是一个12字节BSON类型:

- `Timestamp`: 表示Unix时间以来的秒数的值
- `Machine`: 机器标识 (3字节)
- `Pid`: 进程标识 (2字节)
- `Increment`: 一个计数器,开始于一个随机值(3字节)

在LiteDB中,文档被存储在集合中时,需要一个唯一的`_id`字段来作为主键。因为`ObjectIds`很小,唯一性很高,并且生成很快,LiteDB使用`ObjectIds`作为`_id`字段未指定时的默认值

不同于Guid数据类型,ObjectIds是有序的,因此更适合于索引。ObjectIds使用十六进制数字的字符串表示。

```C#

var id = ObjectId.NewObjectId();

// 你可以从一个ObjectId获取创建时间
var date = id.CreationTime;

// ObjectId 用十六进制值表示
Debug.WriteLine(id);
"507h096e210a18719ea877a2"

// 基于十六进制表示法创建一个实例
var nid = new ObjectId("507h096e210a18719ea877a2");
```
83 changes: 83 additions & 0 deletions v3/DbRef.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
LiteDB是一个文档数据库,因此集合间没有连接。你可以使用嵌入文档(子文档)或在集合间创建一个引用。要创建这个引用,你可以使用`[BsonRef]`属性,或从Fluent API映射器中使用`DbRef`方法。

### 在数据库初始化时映射一个引用

```C#
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
}

public class Order
{
public int OrderId { get; set; }
public Customer Customer { get; set; }
}
```

如果你不做任何映射,当你保存一个`Order``Customer`会被保存为一个嵌入的文档(没有链接到任何其他集合)。如果你改变`Customer`集合中的顾客名称,这个更改不会影响`Order`集合。

```JS
Order => { _id: 123, Customer: { CustomerId: 99, Name: "John Doe" } }
```

如果你想顾客引用只存储在`Order`集合,你可以装饰你的类:

```C#
public class Order
{
public int OrderId { get; set; }

[BsonRef("customers")] // 这里"customers"是Customer集合名称
public Customer Customer { get; set; }
}
```

或使用Fluent API:

```C#
BsonMapper.Global.Entity<Order>()
.DbRef(x => x.Customer, "customers"); // 这里"customers"Customer集合名称
```

现在,当你存储`Order`时,你将只存储链接引用。

```JS
Order => { _id: 123, Customer: { $id: 4, $ref: "customers"} }
```

### 查询结果

当你使用一个交叉集合引用查询一个文档,你可以在查询前使用`Include`方法自动加载引用。

```C#
var orders = db.GetCollection<Order>("orders");

var order1 = orders
.Include(x => x.Customer)
.FindById(1);
```

DbRef也支持`List<T>``Array`,像这样:

```C#
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

public class Order
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public List<Product> Products { get; set; }
}

BsonMapper.Global.Entity<Order>()
.DbRef(x => x.Products, "products");
```

如果从数据文件恢复时你的`Products`字段是null或空列表,LiteDB将什么也不做(respect)。如果你在查询中不使用`Include`,类被加载时,只会设置`ID`(所有其他属性会一直是默认/null值)。
74 changes: 74 additions & 0 deletions v3/FileStorage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
LiteDB限制一个文档大小为1Mb,以保持内存占用不是很大。对于文本文档来说,这是一个很大的尺寸。但对于很多二进制文件来说,1Mb就太小了。因此LiteDB实现了`FileStorage`,一个用于存储文件和流的自定义集合。

LiteDB使用两个特殊的集合来分裂文件内容到多个分块(chunks):

- `_files` 集合只存储文件引用和元数据

```JS
{
_id: "my-photo",
filename: "my-photo.jpg",
mimeType: "image/jpg",
length: { $numberLong: "2340000" },
uploadDate: { $date: "2015-01-01T00:00:00Z" },
metadata: { "key1": "value1", "key2": "value2" }
}
```

- `_chunks` 集合按1MB分块存储二进制数据。

```JS
{
_id: "my-photo\00001",
data: { $binary: "VHlwZSAob3Igc ... GUpIGhlcmUuLi4" }
}
{
_id: "my-photo\00002",
data: { $binary: "pGaGhlcmUuLi4 ... VHlwZSAob3Igc" }
}
{
...
}
```

文件用`_id`字符串值标识,遵循下列规则:

- 以字符,数字,`_`, `-`, `$`, `@`, `!`, `+`, `%`, `;``.` 开头
- 如果包含一个 `/`,必须紧跟以上字符

要更好地组织很多文件,你可以使用`_id`作为一个`directory/file_id`。这是一个不错的方案,这样可以使用`Find`方法快速查找一个文件夹下的所有文件。

示例: `$/photos/2014/picture-01.jpg`

`FileStorage`集合包含简单的方法,如:

- **`Upload`**: 发送文件或流到数据库。可以用于文件或`Stream`。如果文件已存在,文件内容会被覆盖。
- **`Download`**: 从数据库获取你的文件,并复制到`Stream`参数。
- **`Delete`**: 删除一个文件引用和所有数据分块
- **`Find`**: 在`_files`集合中查找很多文件中的一个。返回`LiteFileInfo`类,稍后它可以用于下载数据。
- **`SetMetadata`**: 更新已存储文件的元数据。这个方法不改变已存储文件的值。它更新`_files.metadata`的值。
- **`OpenRead`**: 按`_id`查找文件,并返回一个`LiteFileStream`将文件内容读取为流

```C#
// 从文件系统上传一个文件
db.FileStorage.Upload("$/photos/2014/picture-01.jpg", @"C:\Temp\picture-01.jpg");

// 从一个流上传一个文件
db.FileStorage.Upload("$/photos/2014/picture-01.jpg", stream);

// 只查找文件引用 - 如果没有找到返回null
LiteFileInfo file = db.FileStorage.FindById("$/photos/2014/picture-01.jpg");

// 现在,加载二进制数据并保存到文件系统
file.SaveAs(@"C:\Temp\new-picture.jpg");

// 或者获取二进制数据为流并复制到另一个流
file.CopyTo(Response.OutputStream);

// 查找一个"directory"中的所有文件引用
var files = db.FileStorage.Find("$/photos/2014/");
```

`FileStorage`不支持事务,以防止将变化保存到磁盘前,把文件的所有内部都放进内存。但每个数据分块都使用事务。每个上传的数据分块都在一个单独的事务中提交。

当上传每一个分块时,`FileStorage`在地址`0`位置保存`_files.length`。当所有分块上传完成时,`FileStorage`对每一个分块的大小进行合计并更新`_files.length`。如果你尝试下载一个0字节长度的文件,下载的文件将是损坏的。一个毁坏的文件并不一定意味着一个损坏的数据库。
Loading

0 comments on commit 43d8ae0

Please sign in to comment.