世の中に出回っている他の多くのドキュメントを再ハッシュするのではなく、Redis+ServiceStackのRedisクライアントに関する背景情報をいくつかリストアップします。
- NoSQLRedisアプリケーションを設計する際の考慮事項
- Redisを使用したNoSQLデータベースの設計
- Redisと.NETの概要
- C#Redisクライアントを使用したスキームレスバージョン管理とデータ移行
魔法はありません-Redisは空白のキャンバスです
まず、Redisをデータストアとして使用すると、空白のキャンバスが提供されるだけであり、それ自体に関連するエンティティの概念がないことを指摘しておきます。つまり、分散型のcomp-sciデータ構造へのアクセスを提供するだけです。リレーションシップがどのように保存されるかは、Redisの基本的なデータ構造操作を使用することにより、最終的にはクライアントドライバー(つまり、ServiceStack C#Redisクライアント)またはアプリ開発者次第です。すべての主要なデータ構造がRedisに実装されているため、基本的に、データを構造化して保存する方法を完全に自由に設定できます。
コードで関係をどのように構成するかを考えてください
したがって、Redisにデータを格納する方法を考える最良の方法は、データがRDBMSテーブルに格納される方法を完全に無視し、データがコードに格納される方法を考えることです。つまり、メモリ内の組み込みのC#コレクションクラスを使用します。これは、Redisがサーバー側のデータ構造との動作を反映しています。
関連するエンティティの概念はありませんが、Redisの組み込みのセット およびSortedSet データ構造は、インデックスを格納するための理想的な方法を提供します。例えば。 Redisのセット コレクションは、要素の最大1つのオカレンスのみを格納します。つまり、アイテム/キー/ IDを安全に追加でき、アイテムがすでに存在するかどうかを気にする必要はありません。1回または100回呼び出しても最終結果は同じになります。つまり、べき等であり、最終的には1つの要素のみが保存されます。セット。したがって、オブジェクトグラフ(集約ルート)を保存する場合の一般的な使用例は、モデルを保存するたびに子エンティティID(別名外部キー)をセットに保存することです。
データの視覚化
エンティティがRedisにどのように保存されるかを適切に視覚化するには、ServiceStackのC#Redisクライアントで適切に機能するRedis管理UIをインストールすることをお勧めします。これは、以下のキー命名規則を使用して、入力したエンティティをグループ化して、優れた階層ビューを提供します(すべてのキーにもかかわらず)同じグローバルキースペースに存在します)。
エンティティを表示および編集するには、編集をクリックします 選択したエンティティの内部JSON表現を表示および変更するためのリンク。モデルがどのように保存されているかを確認できたら、モデルの設計方法についてより適切な決定を下せるようになることを願っています。
POCO/エンティティの保存方法
C#Redisクライアントは、単一の主キーを持つすべてのPOCOで動作します。これは、デフォルトではId
であると想定されています。 (ただし、この規則はModelConfigでオーバーライドできます)。基本的に、POCOは、typeof(Poco).Name
の両方を使用してシリアル化されたJSONとしてRedisに格納されます。 およびId
そのインスタンスの一意のキーを形成するために使用されます。例:
urn:Poco:{Id} => '{"Id":1,"Foo":"Bar"}'
C#クライアントのPOCOは、通常、ServiceStackの高速Jsonシリアライザーを使用してシリアル化されます。この場合、パブリックゲッターを持つプロパティのみがシリアル化されます(パブリックセッターは逆シリアル化されます)。
デフォルトは[DataMember]
でオーバーライドできます attrsですが、POCOを醜くするため、お勧めしません。
エンティティはブロブされます
したがって、RedisのPOCOはブロブされているだけなので、POCOの非集約ルートデータをパブリックプロパティとして保持するだけです(意図的に冗長データを保存する場合を除く)。メソッドを使用して関連データをフェッチすることをお勧めします(シリアル化されないため)が、データを読み取るためにリモート呼び出しを行うメソッドもアプリに通知します。
それで、フィードかどうかについての質問 ユーザーと一緒に保存する必要があります それが非集約ルートデータであるかどうか、つまり、ユーザーのコンテキスト外でユーザーフィードにアクセスするかどうかです。いいえの場合は、List<Feed> Feeds
のままにします User
のプロパティ タイプ。
カスタムインデックスの維持
ただし、すべてのフィードに個別にアクセスできるようにしたい場合、つまりredisFeeds.GetById(1)
次に、それをユーザーの外部に保存し、2つのエンティティをリンクするインデックスを維持する必要があります。
お気づきのように、エンティティ間の関係を保存する方法はたくさんあり、その方法は主に好みの問題です。 親>子の子エンティティの場合 常にParentIdを保存したい関係 子エンティティと。親の場合、 ChildIdsのコレクションを保存することを選択できます モデルを使用してから、すべての子エンティティに対して1回のフェッチを実行して、モデルを再水和します。
もう1つの方法は、親dtoの外部のインデックスを独自のセットで維持することです。 親インスタンスごとに。この良い例は、Redis StackOverflowデモのC#ソースコードにあります。ここでは、Users > Questions
およびUsers > Answers
に保存されます:
idx:user>q:{UserId} => [{QuestionId1},{QuestionId2},etc]
idx:user>a:{UserId} => [{AnswerId1},{AnswerId2},etc]
C#RedisClientには、TParent.StoreRelatedEntities()を介したデフォルトの親/子規則のサポートが含まれていますが、TParent.GetRelatedEntities<TChild>()
およびTParent.DeleteRelatedEntities()
次のようにインデックスがバックグラウンドで維持されるAPI:
ref:Question/Answer:{QuestionId} => [{answerIds},..]
事実上、これらは可能なオプションのほんの一部であり、同じ目的を達成するためのさまざまな方法があり、自分でロールする自由もあります。
NoSQLのスキーマレスでルーズなタイピングの自由を受け入れる必要があり、RDBMSを使用するときに慣れ親しんでいる可能性のある厳密で事前定義された構造に従おうとすることを心配する必要はありません。
結論として、本当の正しい方法はありません データをRedisに保存します。例: C#Redisクライアントは、POCOの周りに高レベルのAPIを提供するためにいくつかの仮定を行い、POCOをRedisのバイナリセーフ文字列値にブロブします-他のクライアントは、代わりにRedisハッシュ(辞書)にエンティティプロパティを保存することを好みます。どちらも機能します。