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
        },

    }
  ]
}

初始的类设计如下:
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

)RavenDb提供了这个Includes的功能去限制反规范化,上一种方式是直接保存了另外一个对象的一些属性,这种方式只是保存了一个引用,当根对象被加载的时候,和它关联的选项也会预加载。
我们可以这样做:
var order = session.Include<Order>(x => x.CustomerId)
    .Load("orders/1234");
//这一句不会在服务端执行
var cust = session.Load<Customer>(order.CustomerId);

)加载多个文档
同时加载"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 > )
    .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当中。

)一对多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);
}

)二级包含关系

二级包含关系是值,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);

)lucene query
var orders = session.Advanced.LuceneQuery<Order2>()
    .Include(x => x.Customer2Id)
    .WhereGreaterThan(x => x.TotalPrice, )
    .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, )
    .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);

RavenDb学习(四)处理文档相关性的更多相关文章

  1. MongoDB学习笔记:文档Crud Shell

    MongoDB学习笔记:文档Crud Shell   文档插入 一.插入语法 db.collection.insertOne() 将单个文档插入到集合中.db.collection.insertMan ...

  2. RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践

    EasyNetQ文档跟进式学习与实践 https://www.cnblogs.com/DjlNet/p/7603554.html 这里可能有人要问了,为什么不使用官方的nuget包呐:RabbitMQ ...

  3. ElasticSearch 5学习(8)——分布式文档存储(wait_for_active_shards新参数分析)

    学完ES分布式集群的工作原理以及一些基本的将数据放入索引然后检索它们的所有方法,我们可以继续学习在分布式系统中,每个分片的文档是被如何索引和查询的. 路由 首先,我们需要明白,文档和分片之间是如何匹配 ...

  4. python 学习之FAQ:文档内容写入报错

    2017.3.29 FAQ 1. 文档内容写入报错 使用with open() as file: 写入文档时,出现'\xa9'特殊字符写入报错,通过print('\xa9')打印输出“©”. > ...

  5. redis module 学习—官网文档整理

    前言 redis在4.0版本中,推出了一个非常吸引的特性,可以通过编写插件的模式,来动态扩展redis的能力.在4.0之前,如果用户想拥有一个带TTL的INCRBY 命令,那么用户只能自己去改代码,重 ...

  6. apidoc学习(接口文档定义取代word)

    apidoc的安装,参考:https://blog.csdn.net/qq_36386771/article/details/82149848 生产文档,需要先编写一个apidoc.json对接口文档 ...

  7. 深入理解DOM节点类型第四篇——文档片段节点DocumentFragment

    × 目录 [1]特征 [2]作用 前面的话 在所有节点类型中,只有文档片段节点DocumentFragment在文档中没有对应的标记.DOM规定文档片段(document fragment)是一种“轻 ...

  8. HTML5学习之跨文档传输消息(七)

    新标准中提供了文档之间直接的消息传输API.而且不限制跨域消息传递! 发送消息使用的是Window对象的postMessage(data,targetURL)方法就可以了,但给哪个window对象发送 ...

  9. jQuery(四)、文档处理

    1 内部插入 1.1 append(content | fn) 向每个匹配的元素内部追加内容. 参数: (1) content:要追加到目标中的内容. (2) function(index, html ...

随机推荐

  1. C++ error: passing 'const std::map<>]' discards qualifiers或pass-by-reference-to-const-map导致的“discards qualifiers”

    产生问题的场景: int func(const map<int, string> &aMap) { string value = amap[0]; } 或者 int  Test:: ...

  2. 关于解决多台linux服务器间的文件实时同步问题

    最近要做一个相关的解决方案,在虚拟机测试没有问题.给大家分享出来,有更好的解决方案,欢迎讨论. 1.1 inotify相关介绍 1.rsync 与传统的cp.tar备份方式相比,rsync具有安全性高 ...

  3. [LeetCode] Meeting Rooms I & II

    Meeting Rooms Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s ...

  4. 我的Eclipse设置

    1.默认编码改成:UTF-8(在老项目里设置此项可能导致java源码文件注释显示乱码!可以手工输入GBK三个字母,然后点apply) 2.文件默认打开方式 3.背景颜色(#C0C0C0,RGB(192 ...

  5. python中包含UTF-8编码中文的列表或字典的输出

    在python 下面一个包含中文字符串的列表(list)或字典,直接使用print会出现以下的结果: >>> dict = {"asdf": "我们的p ...

  6. elasticsearch简介和倒排序索引介绍

    介绍 我们为什么要用搜索引擎?我们的所有数据在数据库里面都有,而且 Oracle.SQL Server 等数据库里也能提供查询检索或者聚类分析功能,直接通过数据库查询不就可以了吗?确实,我们大部分的查 ...

  7. linux:文件及文件夹管理

    http://blog.csdn.net/pipisorry/article/details/39854265 查看用户的信息 pika:~$id pikauid=1000(pika) gid=100 ...

  8. Android-一只手指滑动View,另一只手指按Home键,重新进入后View状态无法更新的问题

    上午测试报了一个bug:说是一只手指拖动虚拟摇杆上的View滑块不松,另一只手指点击Home键将App压后台,重新进入的时候,View滑块卡死了. 刚开始看到这个问题感觉很奇怪,因为正常情况下,手指离 ...

  9. Python 3.6 安装pip

    1.首先python3.4以后,pip内嵌,不过使用方法是: python -m pip install django 2.如果你觉得上面的指令太长,想用旧方法使用pip,那用以下指令安装pip即可 ...

  10. pandas数组(pandas Series)-(2)

    pandas Series 比 numpy array 要强大很多,体现在很多方面 首先, pandas Series 有一些方法,比如: describe 方法可以给出 Series 的一些分析数据 ...