2017-09-27 11 views
2

私たちは、現在考えられているオブジェクト設計上の問題についてよく考えていないようです。複雑なRavenDbオブジェクトのレイジーローディング

RavenDbデータベースには、何千ものルート集約オブジェクトが格納されています。特定の大規模顧客にとって、これらのオブジェクトは、Web操作(ページのオープン、データの保存など)を効果的に実行するには大きすぎます。次のように

構造は次のとおりです。 Accountオブジェクトは、その下に集約ルート で、小さなオブジェクトとサイズがすべての「罰金」ですコレクションの茄多があり、非常に大きくなるとことができ呼ばれる1つのコレクションの資源を除いルートオブジェクトが複数のメガバイトのサイズになるようにします。これにより、アカウントとその内部データの基本的なCRUD操作が非常に遅くなります

リソースコレクション内のオブジェクトは、それ自体が巨大ではありませんが、独自の子を持ち、それらはサイズを上げてドラッグします。 各リソースオブジェクトには、メトリック、アクション、アラート、スケーリング、その他の「重い」コレクションがあります。

コードベースは数十万行のスーパーコンプレックスです。そして数百コード参照の行数千人のいない場合、リソースの収集とその中にリソースオブジェクトを検査しますが、それぞれのリソースオブジェクトの基礎となる子コレクションへのアクセスは不定期と、ほとんどの時間で

質問を一つの資源をやっように見える :Accountオブジェクト、その他のすべての子オブジェクト、オブジェクト、および最初のレベルのResourceオブジェクトだけをロードするには、リソースの遅延サブタイプをロードしますか?

+0

そこで質問は何ですか? – Bestter

+0

"アカウントオブジェクト、その他のすべての子やオブジェクト、そして最初のレベルのリソースオブジェクトだけをロードしてから、リソースのレイジーロードサブフォルダ(遅延ロード可能な特定のコレクションが7つあります) ) " – Igorek

+0

@Igorekは私の答えであなたの問題を解決しましたか? –

答えて

2

はどのように我々は、そのすべてをAccountオブジェクトをロードしない私たちは、データのロード/セーブする責任がある単一のリポジトリを持って

(レイジーロードすることができます7つの特定のコレクションのようにあります)リソースオブジェクトの最初のレベルのみ、そしてResourcesのサブレイヤを遅延ロードしますか? (遅延読み込みが可能な7つの特定のコレクションがあります)

Ravenでロードオンデマンドを行うのはかなり簡単です。これを行うには、リソースに遅延読み込みを行い、自分のドキュメントにしたいものを持たせてから、親にIDのコレクションを持たせるだけです。

前:

class Resource 
{ 
    public List<Foo> Foos { get; set; } 
    public List<Bar> Bars { get; set; } 
    // ... etc 
} 

後:あなたのFooとバーのオブジェクトのよう

class Resource 
{ 
    // These are the things we need to lazy load. 
    public List<string> FooIds { get; set; } 
    public List<string> BarIds { get; set; } 
} 

(リソースの遅延ロードされた子供)、あなたは自分の文書としてそれらを.Storeする必要があります。

これを実行すると、リソースを読み込んでもすべての子オブジェクトが読み込まれるわけではなく、読んだり書いたりするときにパフォーマンスが向上します。

しかし、それらの子供を読み込む必要はありますか?つかいます 。インクルード:

// 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); 
} 
0

どのように我々は、Accountオブジェクトをロードし、その雑多な子供 とオブジェクトのすべて、およびリソースオブジェクトの最初のレベルのみ、およびリソースのその後 レイジーロードサブ子どものですか?

OK(レイジーロードすることができます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"); 
関連する問題