0

Entity Framework などの ORM を介してインターフェイスできるように、従来の Microsoft SQL Server データベースを準備しています。私の質問は、共通の型を共有する多対多の関連付けのセットアップの処理に関するものです。具体的には、マスター タイプ間で共通のタイプを共有する必要がありますか、それとも各マスター タイプに独自のリンク テーブルを持たせる必要がありますか。

たとえば、対象のテーブルが現在どのようにセットアップされているかを示す簡単な例を次に示します。

従来の多対多

Teachersof には と の 2 つのタイプがありStudents、どちらにも 0、1、または many を含めることができることに注意してくださいPhoneNumbers。2 つのテーブルTeachersStudentsは、実際には関連付けテーブル ( PeoplePhoneNumbers) を共有しています。フィールドFKIDTeacherIdまたは のいずれかStudentIdです。

私が設定すべきだと思う方法は次のようなものです:

より良い多対多?

このようにして、Teachersテーブルとテーブルの両方がStudents独自の PhoneNumbers テーブルを取得します。

私の腸は、2番目の方法が適切な方法であると教えてくれます。これは本当ですか?PhoneNumbers テーブルに複数のフィールドが含まれている場合でもどうなるでしょうか。私のオブジェクト指向プログラマーの頭脳は、これらのテーブルの唯一の違いがどのマスターテーブルにリンクされているかだけである場合、それぞれが十数個のフィールドを含むいくつかの同一のテーブルを持つのは間違っていると言っています? 例えば:

冗長テーブル

ここでは、同じ情報を含む 2 つのテーブルがありますが、唯一の違いは、1 つのテーブルが のアドレスでTeachersあり、もう 1 つのテーブルが のアドレスであることですStudents。これらは私には冗長で、実際には 1 つのテーブルであるべきだと思いますが、データベースがそれらを制約する能力を失い (そうですか?)、ORM をこれに適用しようとすると、自分にとって厄介になります。

このタイプの共通タイプをマージする必要がありますか、それともマスター タイプごとに分離したままにする必要がありますか?

アップデート

以下の回答により、データベース内のテーブルのサブクラス化に基づく次のソリューションにたどり着きました。最初の問題の 1 つは、エンティティ タイプが他の両方のテーブルに共通していたため、他の複数のテーブル間で共通のテーブルを共有していたことでした。これを処理する適切な方法は、共有テーブルをサブクラス化し、本質的にそれらを共通の親から派生させ、共通のデータ型をこの新しい親にリンクすることです。以下に例を示します (私の実際のデータベースは教師と生徒とは何の関係もないことに注意してください。したがって、この例は非常に作られていますが、概念は有効です)。

解決

TeachersStudentsの両方が必要であるためPhoneNumbers、解決策は、スーパークラス、 、およびテーブルへのPartyFKを作成することです。また、. この例では、さらにサブクラス化し、さらに1 つレベルを下げて から派生させました。PhoneNumbersPartyTeachersStudentsStudentsPartTimeStudentsLearners

このソリューションが非常に満足できるのは、Entity Framework などの ORM に実装する場合です。

クエリは簡単です。特定の電話番号を持つすべての教師と生徒にクエリを実行できます。

var partiesWithPhoneNumber = from p in dbContext.Parties
     where p.PhoneNumbers.Where(x => x.PhoneNumber1.Contains(phoneNumber)).Any()
     select p;

同様のクエリを実行するのも同じくらい簡単ですが、Teachers のみに属する PhoneNumbers に対してのみです。

var teachersWithPhoneNumber = from t in dbContext.Teachers
  where t.Party.PhoneNumbers.Where(x => x.PhoneNumber1.Contains(phoneNumber)).Any()
  select t;
4

4 に答える 4

2

スーパータイプ/サブタイプのパターンを調べる必要があると思います。教師または生徒ごとに 1 つの行を持つPartyまたはテーブルを追加します。Person次に、 と 表で を PK と FK の両方として使用しますPartyID (TeacherただしStudent、とPartyという名前を付けます)。これにより、スーパータイプ テーブルと各サブタイプ テーブルの間に「1 対 0 または 1」の関係が確立されます。TeacherIDStudentID

サブタイプ テーブルに ID 列がある場合は、それらを削除する必要があることに注意してください。今後これらのエンティティを作成するときは、最初にスーパータイプに挿入し、次にいずれかのサブタイプでその行の ID を使用する必要があります。

一貫性を維持するには、ID が他のテーブルと競合しないように、サブタイプ テーブルの 1 つに番号を付け直す必要もあります。SET IDENTITY_INSERT ONその後、不足しているスーパータイプ行を作成するために使用できます。

これらすべてのStudent利点は、そのテーブルに対して FK を実行できるなど、1 つのタイプのみを許可する必要があるテーブルがある場合に、テーブルのように FK を実行できる FK が必要な場合に、テーブルに対して FK を実行できることですAddressParty代わりは。

最後のポイントは、すべての共通の列をスーパータイプ テーブルに移動し、それらの間で異なる必要があるサブタイプの列のみを配置することです。

単一Phoneのテーブルも簡単にリンクできるようになりPartyIDました。

より詳細な説明については、同様の質問に対するこの回答を参照してください。

于 2013-01-13T21:29:48.793 に答える
2

Teacher と Student はどちらも、より一般的な概念 (Person) のサブクラスです。データベース内のすべての人に共有される一般的なデータを含む Person テーブルを作成し、Person にリンクして追加の詳細を含む Student テーブルと Teacher テーブルを作成すると、他のすべてのユーザーにリンクする適切なポイントがあることがわかります。テーブル。

すべての人に共通のデータ (ゼロから多数の電話番号など) がある場合は、Person テーブルにリンクできます。生徒にのみ適切なデータがある場合は、それを生徒 ID にリンクします。学生インストラクターは、学生と教師の両方の記録を持つ単なる個人であるという追加の利点があります。

一部の ORM は、サブクラス テーブルの概念を直接サポートします。LLBLGen は、私が説明した方法でこれを行うので、データ アクセス コードを高レベルの概念 (Teacher と Student) で機能させることができ、Person テーブルは低レベルのデータ アクセス コードでユーザーに代わって管理されます。

編集

現在の図に関するいくつかのコメント (翻訳元のソース ドメインには関係ない可能性があるため、少し塩を加えることをお勧めします)。

パーティー、教師、学習者は良さそうです。給与履歴を追跡できるように、レートの開始日と終了日を追加すると、給与は見栄えがよくなります。また、Salary を持つエンティティが複数ある場合は、(TeacherID の代わりに) PartyID を使用することが理にかなっている可能性があることに注意してください。

PartyPhoneNumbers は、電話番号を直接掛けることができるようです。これは、一度に複数の人 (n:m) の電話番号を変更する予定があるかどうか、または電話番号が各当事者によって個別に所有されているかどうかによって異なります。(私は後者を期待します。なぜなら、(実世界の) 教師の子供である生徒がいて、電話番号を共有している可能性があるためです。生徒の電話番号の更新が教師に影響を与えたくないので、 join table ここでは奇妙に思えます。)

Learners から PaymentHistories は正しいように見えますが、Students と PartTimeStudents の違いは人為的なようです。(PartTimeStudents はより多くの AttendenceDays のように見えますが、これは LearnerClasses 結合の結果となります)。

于 2013-01-13T21:55:52.433 に答える
1

あなたが抱えている問題は、「1 対 1」の関係の一例です。人は、教師または生徒 (あるいはその両方) です。

私は、既存の構造がこの情報を最もよく捉えていると思います。

その人は電話番号を持っています。そして、ある人は教師であり、ある人は学生です。各エンティティに関する追加情報は、教師または生徒のテーブルに格納されます。名前などの一般的な情報は電話テーブルにあります。

電話番号を 2 つの別々のテーブルに分割するのはかなり混乱します。結局のところ、電話番号では、それが生徒用なのか教師用なのかわかりません。さらに、管理スタッフなど、他の電話番号用のスペースがありません。また、時々クラスを教えたり、教えるのを手伝ったりする可能性のある学生にとっても課題があります。

于 2013-01-13T21:03:39.880 に答える
0

あなたの質問を読むと、あなたの状況に共通のデータベース スキーマを求めているようです。過去にいくつか見てきましたが、他のものよりも扱いやすいものもありました。

1 つのオプションは、両方が同じ Address テーブルを使用する Student_Address テーブルと Teacher_Address テーブルを持つことです。このようにして、保存するエンティティ固有のフィールドがある場合、その機能を利用できます。ただし、これはクエリを実行するのが少し (大幅ではありませんが) 難しくなる可能性があります。

別のオプションは、上記で提案した方法です。おそらく、テーブルに主キーを追加するだけです。ただし、そのテーブルに PersonTypeId フィールドを追加する必要があります (PersonType テーブルにリンクする PersonTypeId)。このようにして、各レコードにどのエンティティがあったかがわかります。

2 つの PhoneNumber テーブルを持つことはお勧めしません。すべてを同じテーブルにまとめることで、管理がはるかに簡単になると思います。つまり、学生は単一のエンティティであり、教師は単一のエンティティであり、電話番号は同じものです。

幸運を。

于 2013-01-13T21:06:59.670 に答える