データベース設計。 複合パターン

Web 2.0は、仮想世界で勝利を収めています。 雨の後、ソーシャルネットワークはキノコのように成長します。 写真、ビデオを保存したり、ブログを書いたり、音楽を聴いたりすることができます。 これはすべてコメントすることができ、お気に入りに入れて、コピーすることができます...多くの可能性があり、ソーシャルネットワークのコンテンツは多様で多様であり、これが彼らの利点です。



ここで、ある種の「Vkontakte」のデータベースの構造を想像してください。 提示? そして、あなたは何を見ますか? データを含むテーブルがたくさんありますか? 他に何? 多対多の関係のためのテーブルがたくさん! リレーショナルデータベースの観点からは必要ですが、ロジックの観点からは不必要です。 しかし、それだけではありません。 テーブルのフィールドの中には、膨大な数の「余分な」フィールドがあります。これは、1対多の関係に役立つ外部キーであり、リレーショナル理論の観点からも必要ですが、ロジックの観点からはまったく役に立ちません。



自分のソーシャルネットワークを作成することにしたと想像してください。 その中にユーザーがいることを計画します(ユーザーがいない場合)。 これらのユーザーは、グループに参加し、写真やビデオを保存し、ブログを書くことができます。 データベースの構造を提示したので、複雑なものではないように思われます。 関係の構造が単純であれば、そうです。 ただし、要件は複雑になる場合があります。 ここで、顧客は、コンテンツが同時に複数のユーザーに属し、同時にコミュニティに属している必要があります。 これ(すべてのオブジェクト)にコメントすることができます。 ユーザーが他のユーザーやコミュニティ、コミュニティブログなど、何でも好きなものを保存できるようにするため。 しかし、あなたは他に何が出てくるかわかりません! そして、そのような各要件は、ベースの再設計、新しいテーブル、外部キーの追加を必要とします。 私はコードを書くことについて話していません。 これを取り除く方法はありますか? どういうわけか、データベースを毎回再設計することなく、任意のオブジェクト(読み取りレコード)間の接続を任意に作成できるようにします。



できる! 「Gangs of Four」という本を開き、Compositeパターンの説明を見つけて読みます。



予定



ツリー構造でオブジェクトを構成して、部分全体の階層を表します。 顧客は、個々のオブジェクトおよび複合オブジェクトを統一された方法で解釈できます。 (章全体を読むことをお勧めします)



必要なもの! それでは、このアイデアを目標に適用する方法を見てみましょう。 すぐに発言しますが、これからはアイデア自体についてのみ説明します。 すでに実装されており、実際のプロジェクトで動作しています。現在、このアーキテクチャに基づいて新しいプロジェクトが開発されていますが、コードの詳細を説明する時間はありません。 次の記事のいずれかで、私は間違いなく詳細に説明し、例と実際のコードを示します。



したがって、このアーキテクチャのタスクは、システムオブジェクトを相互に任意に接続できるようにすることです。



検討中のアーキテクチャでは、各オブジェクトはテーブル内のエントリです。 オブジェクトのタイプ(写真、ビデオ、ユーザーなど)ごとに、個別のテーブルがデータベースに作成されます。 このような各テーブルは、オブジェクト+主レコードキーに関連するデータ(つまり、外部キーなし)のみが格納されるフィールドのみで構成されます。 通信は、4つのフィールドで構成されるGUIDという名前のすべての単一テーブルを介して実行されます。 なぜ4つのフィールドがあるのですか? さて、2つのフィールドは理解できます。これは関連オブジェクトのID、つまり外部キーです。 古典的なスキームは多対多です。 しかし結局のところ、IDだけでは、データベース全体でオブジェクトを一意に識別することは不可能です。 異なるテーブルでは、IDを繰り返すことができます(各テーブルのシーケンスは異なります)。 したがって、オブジェクト型の概念が導入されます。 実際、オブジェクトのタイプは、このオブジェクトが保存されているテーブルの名前(または、必要に応じてプログラムコードのクラス名)です。 したがって、ID-TYPEペアは、データベース全体内のオブジェクトの一意の識別子です。 これが、GUIDマッピングテーブルが4つのフィールドで構成されている理由です。最初の2つは上で述べたように、関連オブジェクトのIDで、残りの2つはそれらのタイプです。 オブジェクトのIDとタイプ(親)を知っていると、それに関連付けられているすべてのオブジェクト(子)を選択できます。すべてと特定のタイプの両方です。



これにより、最も奇妙な接続を構築し、システムのビジネス要件の変化に非常に柔軟に対応できます。



そのようなアーキテクチャで私が見る欠点 。 まず、これは巨大なGUIDテーブルです。 結局のところ、その中のレコードの数は、すべてのデータベーステーブルのレコードの数と同じです。 オブジェクトは他の複数のオブジェクトに一度に接続できるため、これは最小限です(ただし、将来的に複数のテーブルに分割しても問題はありません)。

第二に、これらはやや難しい要求です。 1対多の関係が従来のスキームに従って実装されている場合、選択は外部キーのみに従って行われますが、このようなモデルでは外部キーはなく、GUIDテーブルに参加する必要があります



確かに、モデルは、必要に応じて、完全に、または個別のセクション(ボトルネックなど)で古典的なモデルに簡単に変換でき、クライアントに対して完全に透過的です。 実際には、プロジェクトの一部は古典的なスキームに従って動作し、一部は新しいスキームに従って動作しますが、互いに干渉することはありません。



さて、実装に関するいくつかの言葉 。 もちろん、誰も手でリクエストを書きたくないので、データベースを操作するロジック全体はGuidComponentと呼ばれる別のレイヤーに配置されます。 これは、ActiveRecordパターンの一種である基本クラスです。 システムのすべてのオブジェクトはそれを継承します(たとえば、PhotoComponent、VideoComponentなど)。基本クラスであるGuidComponentは、システムの他のオブジェクトを操作したり、リンクとリンクを削除したり、オブジェクトとその関連オブジェクト(子)からデータを受信したりするためのメソッドを各相続人に提供します。 たとえば、オブジェクトをバインドするには、単にaddChild()メソッドを呼び出します。 リンクされたオブジェクトへのリンクをパラメーターとして渡します。



これは簡単なクラス図です(少し時代遅れの真実):







最後に、写真にコメントを追加するサンプルJavaコード:

// id = 10

PhotoComponent photo = new PhotoComponent(10);

CommentComponent comment = new CommentComponent();

comment.setMessage(" ");

comment.save();



photo.addChild(comment);



//

List comments = photo.loadChilds(CommentComponent.class);





, . ( ) , , , . - , , , .







All Articles