web-dev-qa-db-ja.com

アプリケーションでカスタムフィールドをサポートするためのデザインパターンは何ですか?

商用アプリケーションを開発しています。お客様はカスタムフィールドのサポートを求めています。たとえば、顧客フォームにフィールドを追加したいとします。

フィールド値とフィールドに関するメタデータを保存するための既知の設計パターンは何ですか?

今のところ、これらのオプションが表示されます。

オプション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列)を選択しました。現時点では、これが最も簡単に実装できました。要件が複雑になり、サポートするカスタムフィールドの数が増えるため、より厳密に定義されたアプローチに屈折させる必要があるでしょう。

70
Sylvain

オプション3、4、または5が適切である可能性が最も高いという以下のポスターに同意します。ただし、提案された実装にはそれぞれ利点とコストがあります。特定の要件に合わせて選択することをお勧めします。例えば:

  1. オプション1の長所:迅速に実装できます。カスタムフィールドでDBアクションを許可します(検索、並べ替え)。
    オプション1の短所:カスタムフィールドは汎用なので、厳密に型指定されたフィールドはありません。データベーステーブルは、サイズ的には非効率的であり、使用されない多くの無関係なフィールドがあります。許可されるカスタムフィールドの数を予測する必要があります。
  2. オプション2の長所:迅速に実装できます。柔軟で、任意の数とタイプのカスタムフィールドを許可します。
    オプション2の短所:カスタムフィールドでDBアクションを実行できません。これは、後でカスタムフィールドを表示する場合や、顧客ごとにのみデータのマイナーな操作を行う場合に最適です。
  3. オプション3の長所:柔軟性と効率の両方。 DBアクションは実行できますが、無駄なスペースを削減するためにデータはある程度正規化されています。タイプまたはソース情報を指定するために使用できる追加の列を追加するという、unknown(google)の提案に同意します。オプション3の短所:開発時間とクエリの複雑さが少し増加しますが、ここではあまり多くの短所はありません。
  4. オプション4はオプション3と同じですが、入力したデータをDBレベルで操作できる点が異なります。オプション3のリンクテーブルにタイプ情報を追加すると、アプリケーションレベルでより多くの操作を実行できますが、たとえば、DBは比較やソートを実行できません。 3と4のどちらを選択するかは、この要件によって異なります。
  5. オプション5は3または4と同じですが、多くの異なるテーブルにソリューションを適用するためのさらに高い柔軟性があります。この場合のコストは、このテーブルのサイズがはるかに大きくなることです。カスタムフィールドに到達するために多くの高額な結合操作を実行している場合、このソリューションは適切にスケーリングされない可能性があります。

追伸以下に示すように、「設計パターン」という用語は通常、オブジェクト指向プログラミングを指します。データベースの設計問題の解決策を探しています。つまり、設計パターンに関するほとんどのアドバイスは適用できません。

14
Eric Nguyen

アプリケーションコードに関する限り、私にはわかりません。データベースで EAVモデル を使用すると、カスタムフィールドに大きなメリットがあることは知っています。

以下のコメントによると、このモデルで起こり得る最も重大な間違いは、外部キーをそこに入れることです。このモデルにFriendIDやTypeIDなどを配置しないでください。このモデルを一般的なリレーショナルモデルと組み合わせて使用​​し、必要に応じてテーブル列に外部キーフィールドを保持します。

2番目の重大な間違いは、すべての要素で報告する必要があるデータをこのモデルに配置することです。たとえば、このモデルにUsernameのようなものを置くと、ユーザーにアクセスし、ユーザー名を知る必要があるときはいつでも、最高で2nクエリに参加するために自分自身をコミットしました。ここで、nは見ているユーザーの数です。通常、すべてのUser要素にUsernameプロパティが必要になると考えると、これもテーブルの列に残す必要があることが明らかになります。

ただし、カスタムユーザーフィールドでこのモデルを使用している場合は問題ありません。ユーザーがリレーショナルデータを入力していて、EAVモデルが検索にあまり悪影響を及ぼさない状況は多くありません。

最後に、これからデータを結合して、Nice prettyレコードセットを取得しないでください。元のレコードを取得してから、エンティティの一連のレコードを取得します。もしあなたがテーブルに参加したいと思ったなら、おそらく上記のように2番目の間違いを犯したでしょう。

10
Spencer Ruport

オブジェクト指向言語で開発している場合、ここでは アダプティブオブジェクトモデル について説明しています。 oo言語でそれらを実装する方法について書かれた記事はかなりありますが、データストア側を設計する方法についてはそれほど多くの情報はありません。

私が勤務する会社では、リレーショナルデータベースを使用してAOMデータを格納することで問題を解決しました。人、ネットワークデバイス、会社など、ドメイン内のさまざまな「エンティティ」をすべて表示するための中央エンティティテーブルがあります。実際の「フォームフィールド」は、入力されたデータテーブルに格納されるため、1つのテーブルがあります。文字列、1つは日付など。すべてのデータテーブルには、エンティティテーブルを指す外部キーがあります。また、型側、つまり特定のエンティティが持つことができる属性(フォームフィールド)の種類を表すテーブルも必要です。この情報は、データテーブルのデータを解釈するために使用されます。

私たちのソリューションの利点は、エンティティ間の参照、複数値など、コードを変更せずにあらゆるものをモデル化できることです。ビジネスルールと検証をフィールドに追加することもでき、それらはすべての形式で再利用できます。短所は、プログラミングモデルを理解するのがそれほど簡単ではなく、クエリのパフォーマンスが、より一般的なDB設計の場合よりも低下することです。リレーショナルデータベース以外のソリューションがAOMの方が優れていて簡単でした。

動作するデータストアを備えた優れたAOMを構築することは大変な作業であり、高度なスキルを持つ開発者がいない場合はお勧めしません。多分いつの日か、この種の要件に対応するOSソリューションが存在するでしょう。

カスタムフィールドについては、SOで以前に説明されています。

4
Kaitsu

オプション4または5が私の選択です。データが重要な場合は、オプション3で型情報を捨てることはしません(完全な型チェックを自分で実装しようとするかもしれませんが、それはかなり大きな仕事であり、データベースエンジンはすでにそれを実行しています)。

いくつかの考え:

  • CustomFieldsDataType列があることを確認してください。
    • CustomFieldValuesでUDFベースのチェック制約を使用して、CustomFields.DataTypeで指定された列がnull以外であることを確認してください。
    • また、標準のチェック制約を使用して、null以外の値が1つだけであることを確認する必要もあります。
  • 外部キーに関しては、これらを別個のDataType。としてモデル化します。
    • 各潜在的なクロステーブル参照には、独自の列が必要です。参照整合性を維持するため、これは良いことです。
    • とにかく、アプリケーションコードでこれらの関係をサポートする必要があるため、データベースにハードコードされているという事実は、実際には機能を制限しません。
    • ORMを使用している場合は、これもORMでうまく機能します。
  • オプション5の場合、中間テーブルを使用して関係をモデル化します。
    • まだCustomerCustomFieldValueがありますが、代わりにCustomerID列とCustomFieldValueID列のみが含まれます。
  • 方法のすべてのステップで、制約について長い間、しっかりと考えます。これはトリッキーなものであり、1つのミスが原因で完全に混乱する可能性があります。

現在開発中のアプリケーションで使用しています。まだ何の問題もありませんが、EAVの設計はまだ私からの日光を怖がらせています。注意してください。

余談ですが、XMLも良い選択です。直接の経験からはあまりわかりませんが、データ設計を始めるときに検討したオプションの1つであり、かなり有望に見えました。

3
WCWedin

オプション3のようなものが行く方法であり、私は以前にこの方法を使用しました。単一のテーブルを作成して、追加のプロパティとそれに対応する値を定義します。これは、CustomerテーブルとCustomerCustomFieldテーブルの間のそれぞれ1対Nの関係になります。カスタムプロパティとの関係の定義に関する2番目の質問は、検討する必要があります。最初に頭に浮かぶのは、プロパティ値がバインドされているテーブルを含むDataSourceフィールドを追加することです。したがって、基本的にはCustomerCustomFieldは次のようになります。

  1. 顧客ID
  2. 物件
  3. ValueDataSource(nullable)

これにより、特定のデータ構造にバインドするか、単にバインドされていない値を指定できるようになります。このモデルをさらに正規化することもできますが、このようなものでも機能し、コードで処理するのに十分簡単なはずです。

3
Sergey

私は現在、これと同じ問題のあるプロジェクトに取り組んでおり、オプション3を使用することを選択しましたが、FieldType = "list"の場合に備えて、FieldTypeフィールドとListSourceフィールドを追加しました。 ListSourceフィールドは、クエリ、SQLビュー、関数名、またはリストのオプションのリストとなるものにすることができます。私の状況でこのようなフィールドを格納しようとする場合の最大の問題は、このフィールドリストが変更され、ユーザーが後でデータを編集できるようになることです。フィールドリストが変更され、編集に進む場合はどうするか。そのシナリオに対する私の解決策は、リストが変更されていない場合にのみ編集を許可し、変更されている場合は読み取り専用データを表示することでした。

0
jbair

これらの「追加」フィールドが付随的であり、それらを検索する必要がない場合は、通常、オプション2を使用します(ただし、XMLよりもJSONの方が適しています)。カスタムフィールドを検索する場合は、オプション3を行うのは難しくありません。通常、SQLオプティマイザーはそれから妥当なパフォーマンスを得ることができます。

0
Javier