2009-03-03 18 views
5

クラスに同じクラスの別のインスタンスをマップする方法その関係自体にプロパティがある場合自己結合関係に追加のプロパティがある場合のNHibernateマッピング

私はPersonPersonと呼ばれる結合テーブルを使って人と人の間の多対多の関係するテーブルの人

PersonID PersonName PersonAge 
---------------------------------- 
     1 Dave Dee    55 
     2 Dozy     52 
     3 Beaky    45 
     4 Mick     55 
     5 Tich     58 

にマッピングされている人というクラスがあります。

PersonPersonID PersonID RelatedPersonID RelationshipID 
-------------------------------------------------------- 
       1   1    5    1 
       2   3    4    2 
       3   2    1    3 

PersonPersonテーブルに次の属性が必要です。

RelationshipID RelationshipName 
-------------------------------- 
      1 Colleague 
      2 Manager 
      3 Tutor 

This questionとリンク先のpost by Billy McCaffertyは、PersonPerson関係を、PersonPerson表の追加の列のために、通常のJOINからそれ自体のエンティティーに昇格させる必要があると説明しています。しかし、それは何が自己結合であるかを説明していません。違いは、関連する人々をすべてDave Dee(ID = 1)に尋ねると、Tich(ID = 5)を取得するだけでなく、取得する必要があります。Dozy(ID = 2) )同様に、Dave DeeもRelatedPersonID列にあるためです。

これまでの私の解決策は、Personクラスに2つのプロパティを設定することです。

public virtual IList<PersonPerson> PersonPersonForward {get;set;} 
public virtual IList<PersonPerson> PersonPersonBack {get;set;} 

private List<PersonPerson> personPersonAll; 
public virtual List<PersonPerson> PersonPersonAll 
{ 
    get 
    { 
     personPersonAll = new List<PersonPerson>(PersonPersonForward); 
     personPersonAll.AddRange(PersonPersonBack); 
     return personPersonAll; 
    } 
} 

そしてHBMに次のようにあります

<bag name="PersonPersonForward" table="PersonPerson" cascade="all"> 
     <key column="PersonID"/> 
     <one-to-many class="PersonPerson" /> 
</bag> 

<bag name="PersonPersonBack" table="PersonPerson" cascade="all"> 
     <key column="RelatedPersonID"/> 
     <one-to-many class="PersonPerson" /> 
</bag> 

これは些細な事不格好と洗練ようです。 NHibernateは、通常、ほとんどの日常的な問題を洗練された方法で解決します。上記は、これを行うための合理的な方法ですか、それとも良い方法がありますか?

答えて

2

私はそれも好きだと思いますが、このようにモデル化するのは少し不器用です。 私は、特定の人物が関連している人物の集まりを持っていますが、あなたには「後ろの関係」もあります。
これは本当に必要ですか?このバックコレクションを削除してPersonRepositoryのメソッドを指定して、特定の人と何らかの関係を持つすべての人を戻すことができる方法を指定することはできませんか?

ええ、これはちょっとあいまいかもしれませんので、ここにいくつかのコードがあります(簡潔にするため、私は 'virtual'修飾子などを省いています。 、時間の99%でので、私は)私のクラス・マッピングで「怠惰= false」を指定してください。あなたが見ることができるように

public class Person 
{ 
    public int Id {get; set;} 
    public string Name {get; set;} 

    public IList<PersonPerson> _relatedPersons; 

    public ReadOnlyCollection<PersonPerson> RelatedPersons 
    { 
     get 
     { 
      // The RelatedPersons property is mapped with NHibernate, but 
      // using its backed field _relatedPersons (can be done using the 
      // access attrib in the HBM. 
      // I prefer to expose the collection itself as a readonlycollection 
      // to the client, so that RelatedPersons have to be added through 
      // the AddRelatedPerson method (and removed via a RemoveRelatedPerson method). 

      return new List<PersonPerson) (_relatedPersons).AsReadOnly(); 
     } 
    } 

    public void AddRelatedPerson(Person p, RelationType relatesAs) 
    { 
     ... 
    } 

} 

は、一つだけのコレクション残したPersonクラスは、それがPersonPersonのコレクションですこのPersonが持つリレーションシップを表すオブジェクト 特定のPersonとリレーションシップを持つPersonを取得するには、PersonクラスのコレクションではなくPersonを返す特定のメソッドをPersonRepositoryに作成することができます。おもうこれによりパフォーマンスも向上します。

public class NHPersonRepository : IPersonRepository 
{ 
    ... 

    public IList<Person> FindPersonsThatHaveARelationShipWithPerson(Person p) 
    { 
     ICriteria crit = _session.CreateCriteria <Person>(); 

     crit.AddAlias ("RelatedPersons", "r"); 

     crit.Add (Expression.Eq ("r.RelatedWithPerson", p)); 

     return crit.List(); 

    } 
} 

'back-reference'はPersonクラスのメンバーではありません。リポジトリを介してアクセスする必要があります。 これは、エリック・エヴァンスが彼のDDDで言っていることもある - ブック:いくつかのケースでは、あなたの代わりに運ぶためにそれら(=関連オブジェクト)を有していると、関連オブジェクトへのアクセス権を与えることができリポジトリ上の特殊なメソッドを持っている方が良いですオブジェクト自体の周り。

私は、コードをテストしていない、私はちょうどここでそれを入力したので、私はまたなど、構文エラーをチェックしませんでした...しかし、私はそれは私がこれを見るだろうか上のビットを明確にすべきだと思います。あなたは、本質的にdirected graphのモデルを構築してきたようですが、私には見えます

+0

@Frederik Gheysels偉大な答えは、私は今それを試してみましょう。あなたがそれを言ったので、明らかな解決策と思われます! –

+0

@Frederik - 私はリポジトリでこれをやっているのが好きですが、関連するすべてのインスタンスと関係タイプも取り戻す方法はまだ分かりません。 –

+0

私は、指定された人との関係を持つPersonオブジェクトを返します。 Offcourse、これらのPersonオブジェクトには、このPersonが持つすべての関係を含む 'PersonPerson'コレクションがあります。 –

2

、および2つのマッピングPersonPersonForwardPersonPersonBackは、それぞれ発信および着信エッジを表します。

このdirectednessはあなたの関係のタイプのセマンティクスによって補強されている:が一方である-同僚-のは、最も可能性の高いsymmetric relationは-マネージャである-のさがある - - 家庭教師 - のはほぼ確実に非対称です。

私は互換性のあるタイプで、文脈で同じものではありませんしながら、この場合にはデータモデルは、リンクの2つのコレクションことを教えしようとしていると思います。

+0

これはやや工夫した表ですが、私はあなたの意見を取ります。対称関係を非対称関係と同じように扱いたいと思います。対称のものがそれぞれ同じであることを意味するのではないでしょうか? –

+0

はい、そうでなければ有向グラフの無向エッジは、それぞれの方向を指す1組の有向エッジによって表されます。 –

+0

ハイブリッドの半有向グラフを実際に使っている場合は、正規化のためにチェック制約(left-id <= right-id)を使用して対称リレーションシップを独自のテーブルに分離してください。対称を関係的に表現する。 –