LiteDB 是一个文档数据库,因此集合之间没有 JOIN,但可以使用嵌入文档 (子文档) 或在集合之间创建引用。你可以使用 [BsonRef] 特性或在fluent API 映射器中使用 DbRef 方法来创建引用。

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

  1. public class Customer
  2. {
  3. public int CustomerId { get; set; }
  4. public string Name { get; set; }
  5. }
  6. public class Order
  7. {
  8. public int OrderId { get; set; }
  9. public Customer Customer { get; set; }
  10. }

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

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

如果你想让 Order 只存储顾客的引用,你可以修饰你的类:

  1. public class Order
  2. {
  3. public int OrderId { get; set; }
  4. [BsonRef("customers")] // 这里 "customers" 是 Customer 集合的名称
  5. public Customer Customer { get; set; }
  6. }

注意,BsonRef 修饰的是整个将要引用的对象,而不是引用其他集合对象的一个 customerid 整数字段。

或者使用 fluent API:

  1. BsonMapper.Global.Entity<Order>()
  2. .DbRef(x => x.Customer, "customers"); // 这里 "customers" 是 Customer 集合的名称

注意: Customer 需要有一个 [BsonId] 已定义。

现在,当你存储 Order 时,你其实只是在存储链接性的引用。

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

查询结果

当你查询交叉引用其他集合的文档时,你可以使用 Include 方法在查询前自动加载引用。

  1. var orders = db.GetCollection<Order>("orders");
  2. var order1 = orders
  3. .Include(x => x.Customer)
  4. .FindById(1);

DbRef 同时支持 List<T>Array,例如这样:

  1. public class Product
  2. {
  3. public int ProductId { get; set; }
  4. public string Name { get; set; }
  5. public decimal Price { get; set; }
  6. }
  7. public class Order
  8. {
  9. public int OrderId { get; set; }
  10. public DateTime OrderDate { get; set; }
  11. public List<Product> Products { get; set; }
  12. }
  13. BsonMapper.Global.Entity<Order>()
  14. .DbRef(x => x.Products, "products");

从数据文件还原数据时,LiteDB 会检查你的 Products 字段是否为 null 或空列表。如果在查询中不使用 Include,加载时只有 ID 有值 (所有其他属性都保持 default/null 值)。

在 v4 中,此 Include 过程发生在 BsonDocument 引擎级别。当然,也支持任何级别的 Include,只要使用 Path 语法就行:

  1. db.Find("orders", Query.All(), new string[] { "$.Customer", "$.Products[*]" });

如果是 LiteCollectionRepository,也可以使用 Linq 语法:

  1. // 资源库 fluent 语法
  2. db.Query<Order>()
  3. .Include(x => x.Customer)
  4. .Include(x => x.Products)
  5. .ToList();