web-dev-qa-db-ja.com

コードで多対多の関係をモデル化する方法は?

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

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

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

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

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

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

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

27
Natrium

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

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

23
John Saunders
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.

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

  • 上司は制限付きで複数の犬を飼うことができます
  • 犬は複数のボスを持つことができます
  • ボスは同じ犬に対して異なるニックネームを持つことができます。
15
James

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

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);
        }
    }
}

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

7

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

あなたはユニークな情報を持つフィールドを持っているので、私はこれらの関係を多対多で考えるのをやめる傾向があります。

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

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

ただし、犬に名前を付けるか、犬を飼うかは独立しています。

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

2
John Nicholas

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

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

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

1
Graham

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

1
MrTelly

リレーションシップ内の各テーブルの外部キーを使用した単純な多対多のリンクテーブルがある場合は、次のようにモデル化します。ボスには犬のコレクションがあり、犬にはボスのコレクションがあります。

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

1
Jamie Ide

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

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

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

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

-野良犬を治療する獣医のためにソフトウェアが開発され、これらの犬が上司に養子縁組された場合、デザインは次のようになります。どの犬にも上司がいない可能性があり、どの上司にも養子縁組まで犬がいない可能性があります。この場合、OO設計では、この特殊なケースを考慮する必要があります。このケースは最初のケースと少し同じです。したがって、任意のクラスのコレクションを他のクラスに追加できます。ただし、任意のソフトウェアこのようなニーズは他のニーズにも影響します。報告のように。獣医師が上司に養子縁組された犬について懸念がある場合、遅かれ早かれ彼はどの犬が誰に養子縁組されたかを報告するように求めます。文のように(上司に養子縁組された犬) )犬のクラスにボスクラスのコレクションが含まれているとよいでしょう。

私はあなたの質問に適切な答えを与えることができると思います。

0
Murat YILMAZ

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

List<Bosses> BossList;

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

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

0
Mike Burton

何かが足りないと思います。多対多が許可されないのはなぜですか?

public class Boss
{
    Dog[] dogs;
}

public class Dog
{
    Boss[] bosses;
}
0
Greg Dean

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

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

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

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

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

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

0
CraigTP