web-dev-qa-db-ja.com

相互に排他的なサブクラスを持つタイプ/サブタイプデザインパターンでサブタイプのサブタイプを実装する

前書き

この質問が将来の読者に役立つようにするために、私は一般的なデータモデルを使用して、私が直面している問題を説明します。

データモデルは3つのエンティティで構成され、ABCのラベルが付けられます。物事をシンプルに保つために、すべての属性はintタイプになります。

エンティティAには次の属性があります:DEおよびX;

エンティティBには次の属性があります:DEおよびY;

エンティティCには次の属性があります:DおよびZ;

すべてのエンティティが共通の属性Dを共有しているため、私はtype/subtype設計を適用することにしました。

重要:エンティティは相互に排他的です!これは、エンティティがA、B、またはCのいずれかであることを意味します。

問題:

エンティティAおよびBには、もう1つの共通属性Eがありますが、この属性はエンティティCには存在しません。

質問:

上記の特性を使用して、可能であればデザインをさらに最適化します。

正直なところ、これを行う方法も、どこから始めればよいかわからないので、この投稿。

Martin Fowlerによると、テーブル継承の問題には3つのアプローチがあります。

  • 単一テーブルの継承 :1つのテーブルがすべてのタイプを表します。未使用の属性はNULLになります。
  • コンクリートテーブルの継承 :具象タイプごとに1つのテーブル、タイプの各属性の各テーブル列。テーブル間の関係はありません。
  • クラステーブルの継承 :タイプごとに1つのテーブル。各テーブルには、継承されていない新しい属性の属性のみがあります。テーブルは、実際の型継承階層を反映して関連付けられています。

これらを出発点として、各アプローチの長所と短所を探すことができます。その要点は、allアプローチには大きな欠点があり、noneには圧倒的な利点があります。 オブジェクトリレーショナルインピーダンスミスマッチ として知られるこの問題は、まだ解決策を見つけることができません。

個人的に、悪いリレーショナル設計がもたらす可能性のある問題のタイプは、悪いタイプから発生する問題の種類よりもはるかに深刻であることがわかりました 設計。データベースの設計が悪いと、クエリが遅くなり、更新の異常、データサイズの急増、デッドロック、応答のないアプリ、数十から数百ギガバイトのデータが誤った形式で沈み込みます。不正な型の設計は、ランタイムではなくcodeの保守と更新を困難にします。したがって、私の本では、正しいリレーショナル設計がすべてのOO型の純度を何度も繰り返し上回っています。

18
Remus Rusanu

あなたの仕様の私の解釈によると、2つの異なる(ただしconnected supertype-subtype 構造を実装するメソッドを見つけたいと思っています。

前述のタスクを達成するためのアプローチを公開するために、問題のシナリオに、FooおよびBarと呼ばれる2つの従来のhypotheticalエンティティタイプを追加します。

ビジネスルール

次に、論理モデルの作成に役立ついくつかのステートメントを示します。

  • A Foo is either one Bar or one C
  • A Foo is categorized by one FooType
  • A Bar is either one A or one C
  • A Bar is classified by one BarType

論理モデル

そして、結果のIDEF1X [1]  論理モデルを 図1 に示します(そして、 = DropboxからPDF としてダウンロードすることもできます):

Figure 1 - Hypothetical Supertype-Subtype Relationships Data Model

フーとバーの追加

モデルをより見栄えよくするためにFooBarを追加しませんでしたが、より表現力を高めるためです。次の理由により、これらは重要であると思います。

  • ABEという名前の属性を共有するため、この機能が異なる(ただし関連する)種類のサブエンティティタイプであることを示しますコンセプトイベントpersonMeasurementなど。これは、Barスーパーエンティティタイプを使用して表しています。これは、Fooのサブエンティティタイプであり、D属性を上部に保持しています。階層。

  • Cは、議論中の残りのエンティティタイプ(つまり、D)と1つの属性のみを共有するため、この側面ほのめかしは、別の種類のサブエンティティタイプコンセプトeventpersonMeasurementなどなので、この状況をFooスーパーエンティティタイプのおかげで描きました。

ただし、これらは単なる仮定であり、リレーショナルデータベースは特定のビジネスコンテキストのセマンティクスを正確に反映することを目的としているため、すべての対象物を特定して分類する必要があります。特定のドメイン。正確に、より多くの意味を捉えることができます。

設計段階での重要な要素

すべての用語を別にしておくと、排他的なスーパータイプとサブタイプのクラスターは通常の関係であることを認識しておくと非常に便利です。次のように状況を説明します。

  • 排他的上位エンティティタイプの出現は、1つのサブエンティティタイプ補数にのみ関連しています。

したがって、これらの場合には、1対1(1:1)の対応(またはカーディナリティ)があります。

以前の投稿からわかるように、discriminator属性(列、実装されている場合)は、この性質のAssociationを作成するときに最も重要な役割を果たします。スーパータイプはconnectedです。 (i)スーパータイプから(ii)サブタイプへのPRIMARY KEYの移行も重要な意味を持っています。

具体的なDDL構造

次に、上記の論理モデルに基づくDDL構造を記述しました。

CREATE TABLE FooType -- Look-up table.
(
    FooTypeCode     CHAR(2)  NOT NULL,
    Description     CHAR(90) NOT NULL, 
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_FooType             PRIMARY KEY (FooTypeCode),
    CONSTRAINT AK_FooType_Description UNIQUE      (Description)
);

CREATE TABLE Foo -- Supertype
(
    FooId           INT      NOT NULL, -- This PK migrates (1) to ‘Bar’ as ‘BarId’, (2) to ‘A’ as ‘AId’, (3) to ‘B’ as ‘BId’, and (4) to ‘C’ as ‘CId’.
    FooTypeCode     CHAR(2)  NOT NULL, -- Discriminator column.
    D               INT      NOT NULL, -- Column that applies to ‘Bar’ (and therefore to ‘A’ and ‘B’) and ‘C’.
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_Foo                 PRIMARY KEY (FooId),
    CONSTRAINT FK_from_Foo_to_FooType FOREIGN KEY (FooTypeCode)
        REFERENCES FooType (FooTypeCode)
);

CREATE TABLE BarType -- Look-up table.
(
    BarTypeCode CHAR(1)  NOT NULL,  
    Description CHAR(90) NOT NULL,  
    CONSTRAINT PK_BarType             PRIMARY KEY (BarTypeCode),
    CONSTRAINT AK_BarType_Description UNIQUE      (Description)
);

CREATE TABLE Bar -- Subtype of ‘Foo’.
(
    BarId       INT     NOT NULL, -- PK and FK.
    BarTypeCode CHAR(1) NOT NULL, -- Discriminator column. 
    E           INT     NOT NULL, -- Column that applies to ‘A’ and ‘B’.
    CONSTRAINT PK_Bar             PRIMARY KEY (BarId),
    CONSTRAINT FK_from_Bar_to_Foo FOREIGN KEY (BarId)
        REFERENCES Foo (FooId),
    CONSTRAINT FK_from_Bar_to_BarType FOREIGN KEY (BarTypeCode)
        REFERENCES BarType (BarTypeCode)    
);

CREATE TABLE A -- Subtype of ‘Bar’.
(
    AId INT NOT NULL, -- PK and FK.
    X   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_A             PRIMARY KEY (AId),
    CONSTRAINT FK_from_A_to_Bar FOREIGN KEY (AId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE B -- (1) Subtype of ‘Bar’ and (2) supertype of ‘A’ and ‘B’.
(
    BId INT NOT NULL, -- PK and FK.
    Y   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_B             PRIMARY KEY (BId),
    CONSTRAINT FK_from_B_to_Bar FOREIGN KEY (BId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE C -- Subtype of ‘Foo’.
(
    CId INT NOT NULL, -- PK and FK.
    Z   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_C             PRIMARY KEY (CId),
    CONSTRAINT FK_from_C_to_Foo FOREIGN KEY (FooId)
        REFERENCES Foo (FooId)  
);

この構造を使用すると、ベーステーブル(または relations )でのNULLマークの格納を回避できます。これにより、データベースが不明確になります。

整合性、一貫性、その他の考慮事項

データベースを実装したら、(a)各排他的スーパータイプ行が対応するサブタイプの対応する行によって常に補完されていることを確認し、次に(b)そのような_を保証する必要があります。subtype行は、スーパータイプdiscriminator列に含まれる値と互換性があります。したがって、データベースでこれらの条件が確実に満たされるようにするために、ACID TRANSACTIONS を使用すると非常に便利です。

データベースの論理的な健全性、自己表現、正確さをあきらめてはいけません。これらは、データベースをより強固にする要素です。

以前に投稿された2つの回答には、データベースとそのアプリケーションプログラムを設計、作成、および管理する際に考慮する価値のある適切なポイントがすでに含まれています。

VIEW定義によるデータの取得

さまざまなスーパータイプ-サブタイプgroupsの列を結合するビューを設定できるため、必要なJOIN句を毎回作成することなく、手元のデータを取得できます。このようにして、目的のビュー(派生リレーションまたは table )から直接簡単に選択できます。

ご覧のように、「テッド」コッドは間違いなく天才でした。彼が遺贈したツールは非常に強力でエレガントであり、もちろんお互いによく統合されています。

関連資料

スーパータイプとサブタイプの関係を含む広範なデータベースを分析する場合は、 extraordinary @PerformanceDBA によって提案された次のスタックオーバーフローの質問に対する回答の価値があります。


注意

1.情報モデリングの統合定義IDEF1X )は、 standard 1993年12月、米国国立標準技術研究所( [〜#〜] nist [〜#〜] )。 (a) E. F. Codd博士が作成した初期の理論的資料にしっかりと基づいています。 (b)Entity-Relationship データのビュー- Dr。P. P. Chen によって作成されました。また、(c)には、Robert G. Brownによって作成された論理データベース設計手法も含まれています。 IDEF1Xが一次論理によって形式化されたことは注目に値します。

6
MDCCL