看起来我们正在处理一个经过深思熟虑的对象设计问题,这个问题现在已经表现为显着的性能/内存问题。
我们有数千个根聚合对象存储在RavenDb数据库中。对于某些大客户来说,这些对象变得太大而无法有效地执行Web操作(打开页面,保存数据等)。
结构如下: 帐户对象是聚合根 在它下面,有许多较小的物体和收藏品,这些物品和收藏品都很好。在大小上,除了一个名为Resources的集合,它可以变得非常大并且可以导致根对象的大小为多兆字节。这会导致帐户及其内部数据的基本CRUD操作执行速度非常慢
资源集合中的对象本身并不庞大,但是它们拥有自己的子级,并且这些对象的大小向上。 每个Resource对象都有Metrics,Actions,Alerts,Scaling以及其他很重的"
我们的代码库非常复杂,有数十万行代码;数百甚至数千行代码引用Resource集合并检查其中的Resource对象,但是对每个Resource对象的底层子集合的访问似乎并不常见,并且大多数一次只完成一个资源
问题:我们如何加载Account对象,所有杂项子对象,以及第一级Resource对象,然后 lazy-load 子 - 资源的孩子? (有7个特定的集合可以延迟加载)
我们有一个负责加载/保存数据的存储库
答案 0 :(得分:2)
我们如何加载Account对象,所有杂项子对象,只加载第一级Resource对象,然后加载资源的延迟加载子子元素? (有7个特定的集合可以延迟加载)
使用Raven进行按需加载非常简单。要做到这一点,让你的资源让你想要延迟加载的东西成为他们自己的文档,然后在父目录上只有一组ID。
在:
class Resource
{
public List<Foo> Foos { get; set; }
public List<Bar> Bars { get; set; }
// ... etc
}
后:
class Resource
{
// These are the things we need to lazy load.
public List<string> FooIds { get; set; }
public List<string> BarIds { get; set; }
}
至于你的Foo和Bar对象(资源的延迟加载子项),你需要将它们存储为自己的文档。
执行此操作后,加载资源将不会加载其所有子对象,从而在读取和写入时为您提供性能提升。
但是当你需要装载这些孩子时呢?使用.Include:
// Query for Resource and include the children in a single remote call.
var resourcesWithChildren = docSession
.Query<Resource>()
.Include(r => r.FooIds) // Include the related Foos
.Include(r => r.BarIds) // Include the related Bars
.Where(...)
.ToList();
foreach (var resource in resourcesWithChildren)
{
// Grab the children; they're already loaded, so this won't induce a remote call.
var foos = docSession.Load<Foo>(resource.FooIds);
var bars = docSession.Load<Bar>(resource.BarIds);
}
答案 1 :(得分:0)
我们如何加载Account对象及其所有杂项子对象 和对象,只有第一级Resource对象,然后 懒惰子资源子项? (有7个特定的 可以延迟加载的集合
好的,我的另一个答案是打破巨大物体的推荐方法;只是让它们成为自己独立的对象。
但是,既然你说你不想做这个工作来解决它们,那么你可以采用另一种方法来做到这一点,那就是使用变压器。使用变换器不会使Raven无法加载大型Account对象及其所有子对象,但由于变换器在服务器上执行,因此它不会通过网络将巨大的对象发送到您的Web服务器。
public class AccountWithFirstLevelResourcesTransformer : AbstractTransformerCreationTask<Account>
{
public AccountWithFirstLevelResourcesTransformer()
{
TransformResults = accs => from acc in accs
select new Account
{
...
Resources = acc.Resources.Select(fullResource => new Resource
{
// Only the properties we want loaded here.
Name = fullResource.Name,
...
})
...
};
}
}
您将在启动期间安装此变压器:
new AccountWithFirstLevelResourcesTransformer().Execute(RavenStore); // RavenStore is your IDocumentStore singleton.
然后您的.Load调用将如下所示:
// This account will have only the first level resources.
var account = dbSession.Load<AccountWithFirstLevelResourcesTransformer, Account>("accounts/1");