ユーザーがWebサイトのテンプレートで使用するフィールドを作成できるcmsシステムを作成しています。 'string'、 'html'、 'integer'などのさまざまなタイプを作成したい。ユーザーはこれらのフィールドをさまざまな値で追加できる必要があるため、少なくとも2つのテーブルが必要になります。
私の質問はこれです:フィールド値タイプごとにテーブルを作成してコードでこれをキャッチする必要がありますか、それともすべてのフィールド値タイプを1つのテーブルに格納する必要がありますか?
オプション1:各タイプのテーブル
+---------------+ +-----------------+ +--------------------+
| Fields | | field_int_value | | field_string_value | etc...
+---------------+ +-----------------+ +--------------------+
| id | | field_id | | field_id |
| field_type_id | | language_id | | language_id |
+---------------+ | value (int) | | value (varchar) |
+-----------------+ +--------------------+
オプション2: 1つのテーブルにすべての値を格納します。未使用の値をNULL
のままにします。
+---------------+ +-----------------+
| Fields | | field_value |
+---------------+ +-----------------+
| id | | field_id |
| field_type_id | | language_id |
+---------------+ | value_int |
| value_string |
| etc... |
+-----------------+
いくつかの例:
たとえば、ユーザーは自分の電話番号を使用して文字列を作成できます。コードでは、テンプレートはこのフィールドを呼び出して電話番号を表示します。ユーザーがこれを変更する場合は、テンプレートの編集について心配することなく、管理者で値を編集するだけで済みます。
もう1つの例は、ユーザーがページに特定の「行動を促すフレーズ」を表示できるようにするブール値です。このブール値は、テンプレートを更新せずにテンプレート内の何かを非表示にするために使用されます。
私のフィールドモデルは、これらすべてを処理するモデルになります。ここでは、特定のタイプのフィールドを取得する関数を作成します。
私は何が最善の選択肢であるかについて頭を悩ませてきましたが、より良い選択肢を見つけることができないようです。誰かアイデアはありますか?
このデータをRDBMS以外の場所に保存するという、@ gbnの提案(質問へのコメント)を軽視しないでください。RDBMSルートを使用することにした場合は、列のある単一のテーブルを使用する方がよいと思います。強く型付けできるように、「型」ごとに。または、すべてのデータを文字列に変換/シリアル化できるため、couldは、単一の文字列フィールドを持つ単一のテーブルを使用できますが、注意が必要です。すべての操作で両方向に適切に変換を行うため。そのテーブルの一部の使用が誤って変換されるか、完全に変換するのを忘れた場合、問題が発生する可能性があります。
単一のテーブルを選択する理由は、ほとんどがロジスティクスです。TypeIDに基づくクエリで異なるテーブルから動的にプルするよりも、COALESCEまたはCASE(またはCASEのような)句に基づいて異なる列を動的に選択する方がはるかに簡単です。行の(少なくとも、すべてのクエリですべての「タイプ」テーブルをLEFT JOINする必要がないわけではありません(そうです!)。
使用しているRDBMSによっては、このモデルを支援するベンダー固有の機能が存在する場合もあります。たとえば、バージョン2008以降のSQL Serverには、NULL可能列に追加できるSPARSE
オプションがあると思います。これにより、NULL値が0バイトを占めることが可能になりますが、通常、固定長フィールド(つまり、[N]VAR{something}
または{something} VARYING
またはXML
ではないほとんどすべてのフィールドまたは一般的にtext
またはSQL_VARIANT
)の場合、常に指定されたバイト数を使用します。欠点は、NULL以外の値の場合、行ごとに4バイト余分に使用されることです。ただし、列がすべての行で75%以上NULLの場合は、巨大な節約になる可能性があります。この機能は、このタイプのモデルに対応するために特別に設計されました。
CHECK CONSTRAINT
があることを確認して、すべてのvalue_
フィールドについて、フィールドがないか、1つだけがNOT NULL
であることを確認してください。
次に、次のような方法でアクセスできます。
COALESCE(value_int, value_string, value_datetime, etc.)
また、SQL Serverを使用している場合(および1つ以上の他のベンダーがこの機能を備えている場合)、「フィルター処理されたインデックス」を使用して、その値がnullでない特定の各value_
フィールドにインデックスを付けることができます。
CREATE NONCLUSTERED INDEX [IX_FieldValues_ValueInt]
ON dbo.[FieldValues] ([ValueInt])
WHERE [ValueInt] IS NOT NULL;
これにより、一般的なCOALESCE
アクセス方法を使用する場合ではなく、特定のValue%
フィールドをターゲットにする場合でも、値を持つ行をターゲットにすることができます。
そして、2つのオプションをもう一度見てみると、実際には、単一のテーブルであるオプションを使用します。 オプション2では、データは実際にはfield_type_id
データの親ではないため、field_value
を分割する目的はあまりないようです。 field_id
は単一の値しか持てませんよね?したがって、field_type_id
をfield_value
テーブルに配置するだけです。そして、それをCHECK CONSTRAINTで使用して、最大で1つのフィールドがNOT NULLであることを確認し、NOTNULLである1つのフィールドがfield_type_id
と一致することを確認します。
最良の設計があるかどうかはわかりませんが、私はいくつかの内部に隠れており、データ型ごとに別々のテーブルを使用していました。また、単一値と複数値の別々のテーブルもあります。
私は確かに複数のテーブルで行きます。列名またはテーブル名/結合を選択する必要があるため、それほど複雑ではありません。ビューを使用することもできます。更新には、より具体的なロックが必要です。
複数の値を検討してください。 joeとsueの両方への電子メールをサポートしたい場合はどうでしょうか。特定のテーブルはオーバーヘッドですが、単純なデータモデルで多くのことを行うのは困難です。
サポートを検討する必要がある仕様があります [〜#〜] cmis [〜#〜] 。明らかに、仕様をサポートする必要はありませんが、相互運用性が必要な場合は、それが最善の方法です。
ただし、CMISをサポートせず、ドキュメント(SQLなし)タイプのバックエンドを持つプレーヤーもいます。
そこにいくつかの素晴らしい無料のオープンソースCMSがあります。