商用アプリケーションを開発しています。お客様はカスタムフィールドのサポートを求めています。たとえば、顧客フォームにフィールドを追加したいとします。
フィールド値とフィールドに関するメタデータを保存するための既知の設計パターンは何ですか?
今のところ、これらのオプションが表示されます。
オプション1:varchar型のField1、Field2、Field3、Field4列をCustomerテーブルに追加します。
オプション2:顧客テーブルにXMLタイプの単一の列を追加し、カスタムフィールドの値をxmlに保存します。
オプション:タイプvarcharの列を持つCustomerCustomFieldValueテーブルを追加し、その列に値を格納します。そのテーブルには、CustomerID、CustomFieldIDも含まれます。
CustomerID, CustomFieldID, Value
10001, 1001, '02/12/2009 8:00 AM'
10001, 1002, '18.26'
10002, 1001, '01/12/2009 8:00 AM'
10002, 1002, '50.26'
CustomFieldIDは、CustomFieldと呼ばれる別のテーブルのIDで、CustomFieldID、FieldName、FieldValueTypeIDの列があります。
オプション4:可能な各値タイプの列を含むCustomerCustomFieldValueテーブルを追加し、右側の列に値を格納します。 #3に似ていますが、フィールド値は厳密に型指定された列を使用して格納されます。
CustomerID, CustomFieldID, DateValue, StringValue, NumericValue
10001, 1001, 02/12/2009 8:00 AM, null, null
10001, 1002, null, null, 18.26
10002, 1001, 01/12/2009 8:00 AM, null, null
10002, 1002, null, null, 50.26
オプション5:オプション3および4は、単一の概念(お客様)に固有のテーブルを使用します。私たちのクライアントは他の形式のカスタムフィールドも求めています。代わりに、システム全体のカスタムフィールドストレージシステムを用意する必要がありますか?したがって、CustomerCustomFieldValue、EmployeeCustomFieldValue、InvoiceCustomFieldValueなどの複数のテーブルを使用する代わりに、CustomFieldValueという名前の単一のテーブルを使用しますか?見た目はエレガントに見えますが、パフォーマンスのボトルネックになりませんか?
それらのアプローチのいずれかを使用しましたか?成功しましたか?どのアプローチを選択しますか?私が考慮すべき他のアプローチを知っていますか?
また、私のクライアントは、カスタムフィールドが他のテーブルのデータを参照できるようにしたいと考えています。たとえば、クライアントが「お気に入りの支払い方法」フィールドを顧客に追加する場合があります。支払い方法はシステムの他の場所で定義されています。それが絵の中に「外部キー」という主題をもたらします。カスタムフィールドテーブルに保存されている値が有効な値であることを確認するために制約を作成する必要がありますか?
ありがとう
======================
2009年7月27日編集:
回答ありがとうございます。アプローチのリストは非常に包括的であるようです。オプション2(単一のXML列)を選択しました。現時点では、これが最も簡単に実装できました。要件が複雑になり、サポートするカスタムフィールドの数が増えるため、より厳密に定義されたアプローチに屈折させる必要があるでしょう。
オプション3、4、または5が適切である可能性が最も高いという以下のポスターに同意します。ただし、提案された実装にはそれぞれ利点とコストがあります。特定の要件に合わせて選択することをお勧めします。例えば:
追伸以下に示すように、「設計パターン」という用語は通常、オブジェクト指向プログラミングを指します。データベースの設計問題の解決策を探しています。つまり、設計パターンに関するほとんどのアドバイスは適用できません。
アプリケーションコードに関する限り、私にはわかりません。データベースで EAVモデル を使用すると、カスタムフィールドに大きなメリットがあることは知っています。
以下のコメントによると、このモデルで起こり得る最も重大な間違いは、外部キーをそこに入れることです。このモデルにFriendIDやTypeIDなどを配置しないでください。このモデルを一般的なリレーショナルモデルと組み合わせて使用し、必要に応じてテーブル列に外部キーフィールドを保持します。
2番目の重大な間違いは、すべての要素で報告する必要があるデータをこのモデルに配置することです。たとえば、このモデルにUsernameのようなものを置くと、ユーザーにアクセスし、ユーザー名を知る必要があるときはいつでも、最高で2nクエリに参加するために自分自身をコミットしました。ここで、nは見ているユーザーの数です。通常、すべてのUser要素にUsernameプロパティが必要になると考えると、これもテーブルの列に残す必要があることが明らかになります。
ただし、カスタムユーザーフィールドでこのモデルを使用している場合は問題ありません。ユーザーがリレーショナルデータを入力していて、EAVモデルが検索にあまり悪影響を及ぼさない状況は多くありません。
最後に、これからデータを結合して、Nice prettyレコードセットを取得しないでください。元のレコードを取得してから、エンティティの一連のレコードを取得します。もしあなたがテーブルに参加したいと思ったなら、おそらく上記のように2番目の間違いを犯したでしょう。
オブジェクト指向言語で開発している場合、ここでは アダプティブオブジェクトモデル について説明しています。 oo言語でそれらを実装する方法について書かれた記事はかなりありますが、データストア側を設計する方法についてはそれほど多くの情報はありません。
私が勤務する会社では、リレーショナルデータベースを使用してAOMデータを格納することで問題を解決しました。人、ネットワークデバイス、会社など、ドメイン内のさまざまな「エンティティ」をすべて表示するための中央エンティティテーブルがあります。実際の「フォームフィールド」は、入力されたデータテーブルに格納されるため、1つのテーブルがあります。文字列、1つは日付など。すべてのデータテーブルには、エンティティテーブルを指す外部キーがあります。また、型側、つまり特定のエンティティが持つことができる属性(フォームフィールド)の種類を表すテーブルも必要です。この情報は、データテーブルのデータを解釈するために使用されます。
私たちのソリューションの利点は、エンティティ間の参照、複数値など、コードを変更せずにあらゆるものをモデル化できることです。ビジネスルールと検証をフィールドに追加することもでき、それらはすべての形式で再利用できます。短所は、プログラミングモデルを理解するのがそれほど簡単ではなく、クエリのパフォーマンスが、より一般的なDB設計の場合よりも低下することです。リレーショナルデータベース以外のソリューションがAOMの方が優れていて簡単でした。
動作するデータストアを備えた優れたAOMを構築することは大変な作業であり、高度なスキルを持つ開発者がいない場合はお勧めしません。多分いつの日か、この種の要件に対応するOSソリューションが存在するでしょう。
カスタムフィールドについては、SOで以前に説明されています。
オプション4または5が私の選択です。データが重要な場合は、オプション3で型情報を捨てることはしません(完全な型チェックを自分で実装しようとするかもしれませんが、それはかなり大きな仕事であり、データベースエンジンはすでにそれを実行しています)。
いくつかの考え:
CustomFields
にDataType
列があることを確認してください。CustomFieldValues
でUDFベースのチェック制約を使用して、CustomFields.DataType
で指定された列がnull以外であることを確認してください。DataType
。としてモデル化します。CustomerCustomFieldValue
がありますが、代わりにCustomerID
列とCustomFieldValueID
列のみが含まれます。現在開発中のアプリケーションで使用しています。まだ何の問題もありませんが、EAVの設計はまだ私からの日光を怖がらせています。注意してください。
余談ですが、XMLも良い選択です。直接の経験からはあまりわかりませんが、データ設計を始めるときに検討したオプションの1つであり、かなり有望に見えました。
オプション3のようなものが行く方法であり、私は以前にこの方法を使用しました。単一のテーブルを作成して、追加のプロパティとそれに対応する値を定義します。これは、CustomerテーブルとCustomerCustomFieldテーブルの間のそれぞれ1対Nの関係になります。カスタムプロパティとの関係の定義に関する2番目の質問は、検討する必要があります。最初に頭に浮かぶのは、プロパティ値がバインドされているテーブルを含むDataSourceフィールドを追加することです。したがって、基本的にはCustomerCustomFieldは次のようになります。
これにより、特定のデータ構造にバインドするか、単にバインドされていない値を指定できるようになります。このモデルをさらに正規化することもできますが、このようなものでも機能し、コードで処理するのに十分簡単なはずです。
私は現在、これと同じ問題のあるプロジェクトに取り組んでおり、オプション3を使用することを選択しましたが、FieldType = "list"の場合に備えて、FieldTypeフィールドとListSourceフィールドを追加しました。 ListSourceフィールドは、クエリ、SQLビュー、関数名、またはリストのオプションのリストとなるものにすることができます。私の状況でこのようなフィールドを格納しようとする場合の最大の問題は、このフィールドリストが変更され、ユーザーが後でデータを編集できるようになることです。フィールドリストが変更され、編集に進む場合はどうするか。そのシナリオに対する私の解決策は、リストが変更されていない場合にのみ編集を許可し、変更されている場合は読み取り専用データを表示することでした。
これらの「追加」フィールドが付随的であり、それらを検索する必要がない場合は、通常、オプション2を使用します(ただし、XMLよりもJSONの方が適しています)。カスタムフィールドを検索する場合は、オプション3を行うのは難しくありません。通常、SQLオプティマイザーはそれから妥当なパフォーマンスを得ることができます。