1. 程式人生 > 其它 >RavenDb學習(四)處理文件相關性

RavenDb學習(四)處理文件相關性

RavenDb是文件型資料庫,但是我們常常也需要定義物件之間的關係,那RavenDb當中是如何處理的呢?
RavenDb提供了優雅的解決方式,使用正確的話,可以減少資料開銷以及網路擁堵
Denormalization

第一種就是反規範化,下面是一個訂單的JSON格式
在Order這個訂單當中我們把我們需要的客戶資訊(名字)也儲存下來了,使用的時候,它直接就讀出來了。

 { // Order document with id: orders/1234
  "Customer": {
    "Name": "Itamar",
    "Id": "customers/2345"
  },
  Items: [
    {
      "Product": {
        "Id": "products/1234",
        "Name": "Milk",
        "Cost": 2.3
        },
      "Quantity": 3
    }
  ]
}

初始的類設計如下:
public class Order
{
    public string CustomerId { get; set; }
    public string[] SupplierIds { get; set; }
    public Referral Refferal { get; set; }
    public LineItem[] LineItems { get; set; }
    public double TotalPrice { get; set; }
}
 
public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
    public short Age { get; set; }
    public string HashedPassword { get; set; }
}

在Order中持有下面這個反規範化的類,而不只是CustomerId
public class DenormalizedCustomer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
}


Includes

1)RavenDb提供了這個Includes的功能去限制反規範化,上一種方式是直接儲存了另外一個物件的一些屬性,這種方式只是儲存了一個引用,當根物件被載入的時候,和它關聯的選項也會預載入。
我們可以這樣做:
var order = session.Include<Order>(x => x.CustomerId)
    .Load("orders/1234");
//這一句不會在服務端執行
var cust = session.Load<Customer>(order.CustomerId);

2)載入多個文件
同時載入"orders/1234", "orders/4321"
var orders = session.Include<Order>(x => x.CustomerId)
    .Load("orders/1234", "orders/4321");
 
foreach (var order in orders)
{
    // this will not require querying the server!
    var cust = session.Load<Customer>(order.CustomerId);
}

另外一種用法:
var orders = session.Query<Order>()
    .Customize(x => x.Include<Order>(o => o.CustomerId))
    .Where(x => x.TotalPrice > 100)
    .ToList();
 
foreach (var order in orders)
{
    // this will not require querying the server!
    var cust = session.Load<Customer>(order.CustomerId);
}

這裡面有兩個通道,當呼叫Load()方式時,呼叫了Results channel,第二個是 Includes channel,被包含的文件是通過它來返回的,並且儲存在session cache當中。

3)一對多Includes
一個訂單,多個提供商
var order = session.Include<Order>(x => x.SupplierIds)
    .Load("orders/1234");
 
foreach (var supplierId in order.SupplierIds)
{
    // this will not require querying the server!
    var supp = session.Load<Supplier>(supplierId);
}

4)二級包含關係

二級包含關係是值,Order類的屬性裡面沒有,是在Order類的屬性Referral的屬性當中有

public class Referral
{
    public string CustomerId { get; set; }
    public double CommissionPercentage { get; set; }
}

var order = session.Include<Order>(x => x.Refferal.CustomerId)
    .Load("orders/1234");
// this will not require querying the server!
var referrer = session.Load<Customer>(order.Refferal.CustomerId);

它也支援集合
var order = session.Include<Order>(x => x.Refferal.CustomerId)
    .Load("orders/1234");
// this will not require querying the server!
var referrer = session.Load<Customer>(order.Refferal.CustomerId);

5)lucene query
var orders = session.Advanced.LuceneQuery<Order2>()
    .Include(x => x.Customer2Id)
    .WhereGreaterThan(x => x.TotalPrice, 100)
    .ToList();
 
foreach (var order in orders)
{
    // this will not require querying the server!
    var cust2 = session.Load<Customer2>(order.Customer2Id);
}



var orders = session.Advanced.LuceneQuery<Order2>()
    .Include("CustomerId")
    .WhereGreaterThan(x => x.TotalPrice, 100)
    .ToList();
 
foreach (var order in orders)
{
    // this will not require querying the server!
    var cust2 = session.Load<Customer2>(order.Customer2Id);
}

Combining Approaches

這種是把前兩種方式結合起來了
public class Order3
{
    public DenormalizedCustomer Customer { get; set; }
    public string[] SupplierIds { get; set; }
    public Referral Refferal { get; set; }
    public LineItem[] LineItems { get; set; }
    public double TotalPrice { get; set; }
}

var order = session.Include<Order3, Customer2>(x => x.Customer.Id)
    .Load("orders/1234");
// this will not require querying the server!
var fullCustomer = session.Load<Customer2>(order.Customer.Id);