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
},
}
]
}
初始的类设计如下:
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学习(四)处理文档相关性的更多相关文章
- MongoDB学习笔记:文档Crud Shell
MongoDB学习笔记:文档Crud Shell 文档插入 一.插入语法 db.collection.insertOne() 将单个文档插入到集合中.db.collection.insertMan ...
- RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践
EasyNetQ文档跟进式学习与实践 https://www.cnblogs.com/DjlNet/p/7603554.html 这里可能有人要问了,为什么不使用官方的nuget包呐:RabbitMQ ...
- ElasticSearch 5学习(8)——分布式文档存储(wait_for_active_shards新参数分析)
学完ES分布式集群的工作原理以及一些基本的将数据放入索引然后检索它们的所有方法,我们可以继续学习在分布式系统中,每个分片的文档是被如何索引和查询的. 路由 首先,我们需要明白,文档和分片之间是如何匹配 ...
- python 学习之FAQ:文档内容写入报错
2017.3.29 FAQ 1. 文档内容写入报错 使用with open() as file: 写入文档时,出现'\xa9'特殊字符写入报错,通过print('\xa9')打印输出“©”. > ...
- redis module 学习—官网文档整理
前言 redis在4.0版本中,推出了一个非常吸引的特性,可以通过编写插件的模式,来动态扩展redis的能力.在4.0之前,如果用户想拥有一个带TTL的INCRBY 命令,那么用户只能自己去改代码,重 ...
- apidoc学习(接口文档定义取代word)
apidoc的安装,参考:https://blog.csdn.net/qq_36386771/article/details/82149848 生产文档,需要先编写一个apidoc.json对接口文档 ...
- 深入理解DOM节点类型第四篇——文档片段节点DocumentFragment
× 目录 [1]特征 [2]作用 前面的话 在所有节点类型中,只有文档片段节点DocumentFragment在文档中没有对应的标记.DOM规定文档片段(document fragment)是一种“轻 ...
- HTML5学习之跨文档传输消息(七)
新标准中提供了文档之间直接的消息传输API.而且不限制跨域消息传递! 发送消息使用的是Window对象的postMessage(data,targetURL)方法就可以了,但给哪个window对象发送 ...
- jQuery(四)、文档处理
1 内部插入 1.1 append(content | fn) 向每个匹配的元素内部追加内容. 参数: (1) content:要追加到目标中的内容. (2) function(index, html ...
随机推荐
- python 视频 图像帧提取
import cv2 vidcap = cv2.VideoCapture('005.avi') success,image = vidcap.read() count = 0 success = Tr ...
- IDEA(2018.01)安装和破解
IDEA(2018.01)安装和破解 1.下载IDE https://www.jetbrains.com/idea/download/#section=windows 选择Ultimate版本 2.下 ...
- Android SDK Manager详解
Android基础知识——Android SDK Manager详解 做Android开发时,免不了使用Android SDK Manager,安装需要的sdk版本.buildTools版本等等. ...
- sudo: /etc/sudoers is owned by uid 755, should be 0
在ubuntu环境下, 想往/etc/sudoers中添加可以执行sudo操作的用户,使用root将/etc/sudoers的权限修改为755后,提示出现标题中的错误: 修正方法:将/etc/sudo ...
- php分享十四:php接口编写
一:加密协议选择 二:常用url传递函数介绍 urlencode 和 rawurlencode 区别是: urlencode把空格变为+号,而rawurlencode编码为20%: base64_en ...
- SQL SERVER 查看数据库信息
a.使用sys.database_files查看有关数据库文件的信息 b.使用sys.filegroups查看有关数据库组的信息. c.使用sys.master_files 查看数据库文件的基本信息和 ...
- Android呼叫管理服务之会话发起协议(SIP)API
原文:http://android.eoe.cn/topic/android_sdk Android提供了一个支持会话发起协议(SIP)的API,这可以让你添加基于SIP的网络电话功能到你的应用程序. ...
- 云服务器 nginx + tomcat 部署集群 配置
nginx.conf #user nobody; worker_processes ; #error_log logs/error.log; #error_log logs/error.log not ...
- vivado 调用UE
- Windows 以管理员运行而不提示
组策略中设置一下:“计算机配置”-“Windows 配置”-“安全设置”-“本地策略”-“安全选项”下:修改“用户帐户控制: 在管理审批模式下管理员的提升提示行为”选项为“提示凭据”就会再弹出提示框了 ...