32

データベースに2つのテーブルがあるとします。例:Dog&Bossこれは多対多の関係です。これは、上司が複数の犬を飼うことができ、犬が複数の飼い主を持つことができるためです。私はボビーの所有者ですが、妻もそうです。

しかし、多対多は許可されていないので、ヘルパーテーブルがあります:DogsPerBoss

これをコードでモデル化する方法は?

クラスボスは犬のコレクションを持つことができます。クラスドッグはボスのコレクションを持つことができます。->少なくとも、それは私が思うことです。おそらくもっと良い解決策がありますか?

ヘルパーテーブルにある追加のデータはどうですか?それはdeBossクラスにするべきですか、それともDogクラスにするべきですか?例:ニックネーム(私は犬を「いい子」と呼び、妻は彼を「わんわん」と呼びます)

私の質問がちょっと明確だといいのですが?これを達成するための最良の方法についてのベストプラクティスはありますか?参考までに教えていただけますか?

ORM(NHibernateのような)はオプションではありません。

4

12 に答える 12

27

なぜあなたはテーブルについて話しているのですか?オブジェクト モデルまたはデータベース モデルを作成していますか?

オブジェクト モデルの場合、Dog が を持つことができずList<Owner>、所有者が を持つことができない理由はありませんList<Dog>。リレーションシップに属性がある場合にのみ、中間クラス (UML ではアソシエーション クラスと呼ばれるもの) が必要です。その場合、追加のプロパティを持つ DogOwnership クラスがあり、各 Owner には がありList<DogOwnership>、各 Dog にも があります。DogOwner には、Dog、Owner、および追加のプロパティがあります。

于 2009-07-09T13:03:06.200 に答える
17
public class Boss
{
   private string name;
   private List<Hashtable> dogs;
   private int limit;

   public Boss(string name, int dogLimit)
   {
      this.name = name;
      this.dogs = new List<Hashtable>();
      this.limit = dogLimit; 
   }

   public string Name { get { return this.name; } }

   public void AddDog(string nickname, Dog dog)
   {
      if (!this.dogs.Contains(nickname) && !this.dogs.Count == limit)
      {
         this.dogs.Add(nickname, dog);
         dog.AddBoss(this);
      } 
   }

   public void RemoveDog(string nickname)
   {
       this.dogs.Remove(nickname);
       dog.RemoveBoss(this);
   }

   public void Hashtable Dogs { get { return this.dogs; } }
}

public class Dog
{
   private string name;
   private List<Boss> bosses;

   public Dog(string name)
   {
      this.name = name;
      this.bosses = new List<Boss>();
   }

   public string Name { get { return this.name; } }

   public void AddBoss(Boss boss)
   {
      if (!this.bosses.Contains(boss))
      {
          this.bosses.Add(boss);
      }
   }

   public void RemoveBoss(Boss boss)
   {
      this.bosses.Remove(boss);
   }  

   public ReadOnlyCollection<Boss> Bosses { get { return new ReadOnlyCollection<Boss>(this.bosses); } }
}

上記は、ボスが複数の犬(制限が適用されている)を持つことができ、犬が複数のボスを持つことができるという関係を維持しています。また、上司が犬を追加するときに、その上司にのみ固有の犬のニックネームを指定できることも意味します。つまり、他のボスは同じ犬を追加できますが、ニックネームは異なります。

制限については、ボスオブジェクトをインスタンス化する前に読み込んだApp.Config値としてこれを使用する可能性があります。したがって、小さな例は次のようになります。

var james = new Boss("James", ConfigurationManager.AppSettings["DogsPerBoss"]);
var joe = new Boss("Joe", ConfigurationManager.AppSettings["DogsPerBoss"]);

var benji = new Dog("Benji");
var pooch = new Dog("Pooch");

james.AddDog("Good boy", benji);
joe.AddDog("Doggy", benji);

james.AddDog("Rover", pooch);
joe.AddDog("Buddy", pooch);  // won't add as the preset limit has been reached.

必要に応じてこれを微調整することはできますが、探しているものの基本はそこにあると思います。

  • 上司は制限付きで複数の犬を飼うことができます
  • 犬は複数のボスを持つことができます
  • ボスは同じ犬に対して異なるニックネームを持つことができます。
于 2009-07-09T13:20:46.113 に答える
7

このようなもの; ただし、まだ微調整が必​​要です (コレクションをプライベートにして、たとえば readonlycollection を返す readonly public アクセサーを追加しますが、ドリフトをキャッチします。

public class Dog
{
    public List<Boss> Bosses;

    public void AddBoss( Boss b )  
    {
        if( b != null && Bosses.Contains (b) == false )
        {
            Bosses.Add (b);
            b.AddDog (this);
        }
    }

    public void RemoveBoss( Boss b )
    {
         if( b !=null && Bosses.Contains (b) )
         {
             Bosses.Remove (b);
             b.RemoveDog (this);
         }
    }
}

public class Boss
{
    public List<Dog> Dogs;

    public void AddDog( Dog d )
    {
         if( d != null && Dogs.Contains (d) == false )
         {
              Dogs.Add(d);
              d.AddBoss(this);
         }
    }

    public void RemoveDog( Dog d )
    {
        if( d != null && Dogs.Contains(d) )
        {
            Dogs.Remove (d);
            d.RemoveBoss(this);
        }
    }
}

このようにして、すべての Dog が自分の Boss を認識し、すべての Boss が自分の Dog を認識しているコードで、多対多をモデル化できます。ヘルパー テーブルに追加のデータが必要な場合は、別のクラスも作成する必要があります。

于 2009-07-09T13:06:33.953 に答える
2

従来の多対多の関係では、一致するテーブルに余分なフィールドはありません。

一意の情報を持つフィールドがあるため、これらの関係を多対多として考えるのをやめがちです。

一致するテーブルに情報を追加したら、このテーブルを独自のエンティティにしたので、それを表す独自のオブジェクトが必要だと思います。

この時点で、コレクションの一部としてこのオブジェクトへの参照を含む、人と犬を接続する DogsName クラスを作成できます。

ただし、犬に呼ばれる名前を付けるか、犬を所有するかは独立しています。

さまざまな人に応じて犬の名前の関係をモデル化するだけでなく、所有関係もモデル化する必要があります。メモリ内では、これは両方のオブジェクトに他のオブジェクトのリストが含まれていることを意味します。

于 2009-07-09T13:06:24.907 に答える
1

私は何かが足りないのですか、それとも次のようにこれに必要な唯一のコードです:

List<Bosses> BossList;

class Dog {}
class Boss { Dog[] Dogs; }

双方向の関係を明示的にモデル化する必要はありません。これは、コード構造に暗黙的に含まれています。これを行う理由は他にもあるかもしれませんが、一般に、一方向の参照と、参照オブジェクトのセットをトラバースする方法があれば十分です。

于 2009-07-09T13:30:03.637 に答える
1

ニックネームを記録する必要がない場合は、犬にはボスのリストがあり、ボスには犬のリストがあるはずです。

DogとBossの関係に属性(この場合はニックネーム)がある場合は、その関係を表すクラスを作成し、DogとBossの両方にそのタイプのリストを保持させる必要があります。

私はしばらくの間 NHibernateを使用してきましたが、この種のオブジェクトリレーショナルインピーダンスの不一致を緩和するのに非常に役立つことがわかりました。

于 2009-07-09T13:00:37.883 に答える
1

これは、多対多が機能しないデータベース、つまりヘルパーテーブルと、多対多が正常に機能するオブジェクトの世界との間の古典的な問題です。リレーションシップに属性があるとすぐに、その情報を保持する新しいクラスを作成する必要があります。ただし、オブジェクト リレーション マッピング (ORM) を見ると、多くの時間を節約できます。このフィールド全体が、DB とオブジェクトの間のこの問題 (および他の多くの問題) を解決するために成長しました。

于 2009-07-09T13:05:06.497 に答える
1

リレーションシップ内の各テーブルからの外部キーを持つ単純な多対多リンク テーブルがある場合は、提案どおりにモデル化します。Boss には Dogs のコレクションがあり、Dog には Bosses のコレクションがあります。

ニックネームなどの追加データを含む多対多の関係がある場合、それを 2 つの 1 対多の関係としてモデル化します。Boss に DogBoss のコレクションがあり、Dog に DogBoss のコレクションがあるように、DogBoss などのエンティティを作成します。

于 2009-07-09T13:05:25.217 に答える
0

実生活と私たちのニーズについて考える必要があるたびに。この場合、どちらがもう一方を持つかがポイントです。

実生活では、犬と上司はお互いを持っていない場合があります。しかし、ソフトウェアのニーズがこの関係に影響を与えるはずです。

  • たとえば、獣医師の患者管理ソフトウェアを開発している場合、野良犬を治す獣医師の場合、患者 (犬) と保護者 (ボス) の関係は次のようになります。ボスには少なくとも 1 匹の犬が必要で、犬にはボスがいない場合があります(次に、ボス ID はこの関係の外部キーです)。これは、設計において、犬のクラスがボスのコレクションを保持する必要があることを意味します。犬なしではボスインスタンスを作成できないためです。この決定は、データ ロジックでも行うことができます。犬とボスのクラスをデータベースに保存しようとするときを考えてみましょう。上記のようなリレーション条件の場合、ボスを保存するときにジャンクション レコードをジャンクション テーブルに挿入する必要があります。

  • 野良犬を治さない獣医師がそのソフトウェアを開発している場合、患者と親の関係は次のようにする必要があります。犬には少なくとも 1 人のボスが必要で、ボスには少なくとも 1 匹の犬が必要です。場合。つまり、これらのクラスのインスタンスはいずれも、お互いがなければ作成できないということです。したがって、OO 設計でこの専門性を定義する必要があります。つまり、この依存関係を表すクラスが必要です。もちろん、この依存関係はジャンクション テーブルに格納されます。

- 野良犬を治療する獣医師のために開発されたソフトウェアと、これらの犬が上司に引き取られた場合、設計は次のようになります。この場合、オブジェクト指向の設計では、この特殊なケースを考慮する必要があります。このケースは最初のケースと少し似ています。したがって、任意のクラスのコレクションを他のクラスに追加できます。ただし、このようなソフトウェアのニーズは、他のニーズに影響を与えます。レポみたいな。獣医師が上司に養子縁組された犬について懸念がある場合、遅かれ早かれ、どの犬が誰に養子縁組されたかについて報告を求めます。(上司に採用された犬) という文のように、犬のクラスに上司のクラスのコレクションが含まれているとよいでしょう。

あなたの質問に適切な回答ができることを願っています。

于 2010-02-06T03:16:02.030 に答える
0

私は何かが欠けていると思います。多対多が許可されないのはなぜですか?

public class Boss
{
    Dog[] dogs;
}

public class Dog
{
    Boss[] bosses;
}
于 2009-07-09T13:03:18.603 に答える
0

リレーショナル モデルでは、多対多の関係をモデル化する最良の方法 (Dogs/Bosses の例を使用) は、3 つの個別のテーブルを持つことです。

DOGS 用の 1 つのテーブル、BOSSES 用の 1 つのテーブル (およびこれらのテーブルのそれぞれに一意のキーがあります)、および 3 番目のテーブルは通常、「ジャンクション テーブル」です。

通常、このテーブルには少なくとも 2 つのフィールドがあります。1 つのフィールドは Dog の外部キー用で、もう 1 つのフィールドは Boss の外部キー用です。このようにして、各犬は多くのボスを持つことができ、各ボスは多くの犬を持つことができます。

さて、これをよりオブジェクト指向の方法でコードでモデル化する場合、これは通常、Dog クラスと Boss クラスを使用することによって実現されます。これらの各オブジェクトの通常のアトミック プロパティを持つだけでなく、それぞれが他のオブジェクトのコレクションであるプロパティも公開します。

たとえば、Dog オブジェクトには「Bosses」というプロパティがあります。このプロパティは、特定の Dog オブジェクト (ジャンクション テーブルで定義) に割り当てられた Boss オブジェクトのコレクションを公開し、反対側では、各 Boss オブジェクトは、割り当てられた Dog オブジェクトのコレクションである Dogs というプロパティを公開します。その特定の Boss オブジェクト (ジャンクション テーブルで定義) に。

これらのオブジェクトにはある程度の「重複」が存在する可能性があることに注意してください (つまり、1 つの「犬」オブジェクトが別の「犬」オブジェクトが持つ「ボス」オブジェクトを持つ場合があります)。ただし、これは 3 テーブル多を変換するための従来のメカニズムです。対多リレーショナル モデルをオブジェクト指向モデルに変換します。

于 2009-07-09T13:08:51.367 に答える
-1

あなたが何を求めているのかわからない。しかし、これはあなたが望むテーブル構造です:

ドッグテーブル

DOG_ID int PK DOG_Name varchar(50)

DogsPerBoss

ID int DOG_ID int BOSS_ID int DogNickName varchar(15)

ボス

BOSS_ID int PK BOSS_Name varchar(50)

于 2009-07-09T13:02:49.320 に答える