多くのORMサイトとSQLチュートリアルでは、これらの関係が明らかであるか、当然と見なされているかのように述べられていますが、なぜ区別が必要なのか完全には理解していません。
両方がidフィールドを持つ2つのテーブルAとB、およびこれら2つのテーブル間のリンケージを考えます。
私の理解は次のとおりです。
1対1の関係:Aに行がある場合、Bには最大で1つの対応する行があり、その逆も同様です。このようなシナリオでは、おそらくテーブルを組み合わせることができると思いますが、それは範囲を超えています。
1対多の関係:Aに行がある場合、Bには対応する行をいくつでも含めることができます。ただし、Bに行がある場合、Aに対応する行は1つだけです。
多対1の関係:すでに2で説明されています。
多対多の関係:Aに行がある場合、Bには対応する行がいくつあってもかまいません。Bに行がある場合、Aには対応する行がいくつあってもかまいません。
では、これが当てはまる場合、なぜORMでこれらのケースを区別する必要があるのでしょうか。 「ここにオブジェクトAがあります。オブジェクトBへの参照または参照のリストを保持しています。」と言うだけでは不十分なのはなぜですか。 「このオブジェクトBへの参照は、1対1の関係です」と明示的に言及する必要があるのはなぜですか。または「これは多対多の関係です」など。
接続の多重度は非常に重要なものだからです。そして、重要な事柄については、魔法の事柄を理解させるよりも、明示する方が良いです。
たとえば、A
にB
への参照のリストがあり、B
にA
への参照のリストがある場合はどうなりますか。これは多対多の関係ですか、それとも2つの多対1の関係ですか?
A
がB
を参照していて、B
がA
を参照しているからといって、同じ接続にはなりません。また、確信が持てない場合は、何もせずにすべてをライブラリのユーザーに任せることをお勧めします。 ORMはオブジェクトモデル自体から十分な情報を取得できません。そのため、エンティティとその多重度の間の接続を適切に確立するには、XMLまたは注釈のいずれかの形式の追加のメタデータが必要です。
別の見方は次のとおりです。多対多の関係で、AのアイテムがアイテムBを参照する場合、システムはBが同じアイテムAを参照し、その逆も同様であることを保証します。 2つの多対1の関係では、これは当てはまりません。 AのアイテムはBのアイテムを参照できますが、同じアイテムBは同じアイテムAを後ろから参照する必要はありません(ただし、参照できます)。
私はあなたに質問があります、この図の2つのケースのクラスはどのように見えるでしょうか:
では、最後に基本的なモデリングを教えてみてください。これらのクラスにはどのような関係がありますか。
class A {
List<B> RelationX;
B RelationY;
}
class B {
A RelationX;
LIST<A> RelationY;
}
ORMは、データベース内のデータのオブジェクト指向表現です。例のように、2つのクラスAとBがあるとします。これらの外部キーの関係をモデル化した参照をデータベースに保存する方法を教えてください。
_class A {
B b;
}
_
または:
_class A {
Collection<B> b;
}
_
それここで問題の核心です:1対1または1対多の関係はありますか?これにより、生成されたコードで使用するデータ構造(生の参照やポインタ、またはコレクション)が変わります。
JavaやC#などの一般的な言語で、ORMと静的型チェックを頻繁に使用するため、これは重要なことです。事前に知っておく必要があるのは、単にではなくwhatオブジェクトのタイプはリンクされていますが、(いくつです。理由は、複数存在する可能性がある場合、オブジェクト参照をコレクションに格納するための間接参照のレベルが必要です。コンパイラは適切な正しいタイプ(B
または_Collection<B>
_)を使用してアクセスします。
これの重要性について少し混乱しているようです。 「AからBへのリンク」を理解するだけでは十分ではなく、カーディナリティについても理解できます。
Amazonなどの一般的なWeb注文システムや、個人情報を入力して商品を購入する他の100のシステムを想像してみてください。
通常は、名前と住所を他の詳細情報とともに入力します。しかし、その声明は巨大ですが、アドレスはいくつありますか?通常、2つのみ:送料と請求で、同じである場合があります。
次に、カーディナリティーが手を振るシステムを想像してみてください。多分私はtwo請求先住所を入力する方法を見つけます。システムはどちらを使用しますか?コードレベルでは、アドレスのコレクションにアクセスしてランダムにアドレスを選択していますか?または、ゼロまたは1を返すCustomer.getBillingAddress()
という名前のメソッドが埋め込まれていますか?コーディングしやすいものは何ですか?
いいえ、データベースのPK/FKレベルと静的に正しい方法を使用してコード内の両方でカーディナリティを適用すると、システムがより堅牢になり、コードを見たときに理解しやすくなります。これは私の顧客の住所に適したコードモデルです。
_class Customer {
Address billingAddress;
Collection<Address> shippingAddresses;
}
_
これで、顧客を管理するコードは請求先住所が1つだけであることを認識していますが、自分、家族、友人などの複数の配送先住所を簡単に入力できます。コードは複数ある可能性があることを認識しており、チェックアウト中にそれらを反復して、選択できるようにします商品の発送先。ただし、クレジットカードに請求する場合は、唯一の請求先住所が使用されます。
あなたの質問について二度考えた後、私はここで他の人とは少し違う答えを出したくなります。
2つのクラスAとBの間の関係についてカーディナリティーを指定せずにオブジェクトモデルを取る場合、ORMは常にそれを潜在的な多対多の関係のように扱うことができます。したがって、技術的には、DBでテーブルAおよびBを生成または使用し、追加のリンクテーブルA_Bを生成し、すべての関連コードを生成できます。 DBの多対多の関係は、1対1または1対多の関係を格納するためにも使用できるため、技術的にこれはうまくいくでしょう。
ただし、このアプローチには2つの大きな欠点があります。
それは非常に無駄になります。 ORMが関係が1対1または1対多であることを事前に知っている場合は、追加のリンクテーブルは必要ないことに注意してください。たとえば、リンクテーブル内の余分なレコードを常に処理する必要があるだけでなく、必要な場合の2倍複雑なSQLステートメントを処理することは、ストレージとCPU時間の大きな浪費です。生成されたクライアントコードについても同様です。単一の値を格納するためだけにクラスでコレクションを取得すると、このコレクションを使用するコードがより複雑になり、より多くのメモリが必要になり、速度が低下する可能性があります。
データベースと生成されたコードデータの整合性を保証することはできませんなので、ビジネスの観点から、リレーションシップは多対多ではなく、1:nまたは1:1である必要があります。周囲のコードで手動でこれを実装する。たとえば、1対1のビジネスケースに使用されるコレクションがある場合、プログラムは最大で1つの値でのみコレクションを埋めることを確認する必要があります。ただし、クラスにコレクションではなく単一のオブジェクトへの参照のみが含まれる場合、それを誤った方法で使用することはできないため、追加のコードは必要ありません。
つまり、技術的には可能ですが、それは非常に無駄であり、データベースプログラミングを容易にするというORMの目標を達成できません。