RavenDBを使用する際の注意事項

すべての良い一日。 RavenDBについてお話します。 それが何であるか知らない人のために、あなたはここで見ることができます 。 将来、何が危機にしているのか知っていると思います。



簡単な紹介



RavenDBはドキュメント指向のデータベースです。 柔軟性があり、快適で、高速であり、まだ多くの利点があることが理解されています...



そして、そうです。





しかし、いくつかの予約で。



最も重要なこと





「RavenDBを使用したプロジェクトアーキテクチャ」を検索するときに最初に遭遇することは、フレーズです。RavenDbをリレーショナルデータベースとして使用しないでください。 ただし、この命題は、NoSQLデータベースを使用する場合には当てはまります。



このフレーズは、必要に応じてデータを非正規化する必要があることを意味します。 RavenDBは、すべての必要な情報を1つのエンティティに保存するという決定を下します。



例を考えてみましょう。



次のエンティティがあるとします。

public class Article { public long Id {get;set;} public string Title {get;set;} public string Content{get;set;} }
      
      





そして、私たちの実体記事にコメントがあるかもしれないという仮定を立ててください。



 public class Comment { public long Id {get;set;} public string Author {get;set;} public string Content{get;set;} }
      
      





データベースにコメント付きの記事を正しく書くために必要なことは次のとおりです。

  1. ArticleクラスにCommentsプロパティを追加
  2. コメントからIDプロパティを削除します。


つまり、コメントは常にエンティティ内にあるため、コメント用に別のテーブルを用意する必要はありません。 これが非正規化のすべてです。



このモデルでは、別のコメントを参照する必要がないため、2番目のポイントを追加しました。 記事に関するすべてのコメント、または一部の著者のすべてのコメントを取得したい場合がありますが、別のコメントは必要ありません。



ところで、RavenDBにはテーブルがありません。 エンティティのコレクションがあり、コレクションに属するエンティティは非常に簡単に設定されます。 しかし、それについては以下で詳しく説明します。



メタデータ



RavenDBがエンティティをJSONオブジェクトの形式で保存することは注目に値します。 その結果、いくつかのサービスプロパティを除き、特定の構造を持ちません。 主なユーティリティプロパティは@metadataです。 このオブジェクトには、ドキュメントのすべての制御データが含まれます。RavenDB内のID、サーバーでの入力(記事など)、および他の多くのプロパティです。



Raven-Entity-Nameプロパティは、コレクションに属するエンティティを担当します。 変更すると、オブジェクトが配置されているコレクションも変更されます。 Idは自動的に変更されません。



ところで、RavenDBの識別子はデフォルトでIdプロパティにマッピングされますが、任意のフィールドを識別子にして、識別子を生成する独自の戦略を定義できます。 ここで詳細に説明します 。 少し下にスクロールするだけです。



ところで、 私が先ほど言った重要なことですが、もう一度繰り返し ます。エンティティ間の関係は悪いです。 エンティティが動作するすべてのものがその中になければなりません。

もちろん、あるエンティティが別のエンティティに属しているかどうかを判断する必要があるときに状況が発生する可能性がありますが、これを絶えず行う必要がある場合は自問してください-RavenDBを正しく使用していて、プロジェクトで必要ですか?



エンティティ検索





ささいなタスクを検討してください-すべての投稿のリストを取得する必要があります。



 List<Blog> blogs = null; using (var session = store.OpenSession()) { blogs = session.Query<Blog>().ToList(); }
      
      







この小さなコードで何が起こるのでしょうか?

まず、RavenDBへの接続を作成します(これは簡単です)。

第二に、セッションは、条件を満たす最初のエンティティを正確に128個提供します。 なぜ128? これがデフォルトの動作だからです。 構成では、この値を1024に増やすことができますが、これは必要な動作ではありません。



これは、RavenDbがページネーションを使用して大量のデータを処理することを強く推奨しているためです。 そして、この振る舞いが既にAPIで記述されていればクールですが、そうではありません! 代わりに、ページネーション用の自転車を毎回作成する必要があります。 最初に、合計ページ数を確認してから、特定のページを取り出す必要があります。

はい、タスクは簡単ですが、迷惑です。



ちなみに、改ページの作業を簡素化するコードは(おそらく、最適ではなく、あなたの観点から)です。

 public static int GetPageCount<T> (this IRavenQueryable<T> queryable, int pageSize) { if (pageSize < 1) { throw new ArgumentException("Page size is less then 1"); } RavenQueryStatistics stats; queryable.Statistics(out stats).Take(0).ToArray(); //     . var result = stats.TotalResults / pageSize; if (stats.TotalResults % pageSize > 0) //   { result++; } return result; } public static IEnumerable<T> GetPage<T>(this IRavenQueryable<T> queryable, int page, int pageSize) { return queryable .Skip((page - 1)*pageSize) .Take(pageSize) .ToArray(); }
      
      







ただし、これだけではありません。

上記の例では、RavenDBは最終更新日でソートされたエンティティを提供します 。 これは、前に説明した@metadataオブジェクトのLast-Modifiedプロパティです。



興味深い事実は、IDでソートできないことです。 エラーがクラッシュするか、何も起こりません。

ソリューションは簡単です-作成済みフィールドを作成し、それでソートします。



クエリにRavenDBを使用する



セッションは30クエリに制限されていることを覚えておく必要があります。この制限が切れると、データベースにクエリを送信しようとすると例外が発生します。 したがって、この素晴らしいデータベースの作成者は、あらゆる方法で、リクエストごとに個別のセッションを作成する必要があることを教えてくれます。 セッションはUnitOfWorkであり、結果として軽量であるため、原則としてこれは正当化されます。 ただし、セッションが絶えず作成されると、コードが読めない外観になってしまう可能性があるため、別の方法で行うことができます。

 private IDocumentSession Session { get { if (_session == null) { _session = _store.OpenSession(); } if (_session.Advanced.NumberOfRequests == _session.Advanced.MaxNumberOfRequestsPerSession) { _session.Dispose(); _session = _store.OpenSession(); } return _session; } }
      
      







プロジェクトでRavenDBを使用する



前述のデータベースの作成者であるAyende Rahienは次のように述べています。「可能な限り高いRavenDBを使用してください。」 また、コントローラーから直接データベースにアクセスする例を示します。 おそらく、小さなプロジェクトの場合、これは正当化されます。 ただし、ユニットテストを備えた古き良き3ユニットを好むため、この方法は私には向いていません。



私の解決策は、必要なことを行うRavenDBセッションでプロキシすることです。

このコンポーネントを作成する主な理由は、セッションモックの難しさです。 それでも何らかの方法でLoadをダンクできる場合、Queryはほとんど非現実的です。 アドインは非常にシンプルですが。



そして、RavenDBを使用したテストについてもう1つ言います。 たぶんこれは、実際のデータベースで作業を確認する必要がある場合に起こります。 この場合、EmbeddableStoreを使用します。

実際のデータベースを使用する理由の1つは、インデックステストです。 しかし、RavenDBのインデックスは広範なトピックであるため、別の記事を書く価値があります。 =)



All Articles