5

その関係自体にプロパティがある場合、クラスを同じクラスの他のインスタンスにどのようにマップしますか?

テーブル Person にマップされている Person というクラスがあります

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

PersonPerson という結合テーブルを使用して、Person と Person の間に多対多の関係が必要です。

 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

この質問とBilly McCafferty によるリンク先の投稿では、PersonPerson テーブルに列が追加されているため、PersonPerson 関係を通常の JOIN から独自のエンティティに昇格させる必要があると説明しています。ただし、自己結合の場合はどうすればよいかは説明されていません。違いは、すべての関係者をDave Dee (ID = 1)に依頼すると、 Tich (ID = 5) だけでなくDozy (ID = 2)も取得する必要があることです。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 は通常、ほとんどの日常的な問題に対する洗練されたソリューションを備えています。上記はこれを行うための賢明な方法ですか、それともより良い方法がありますか?

4

2 に答える 2

2

私もそのようにすると思いますが、このようにモデル化するのは少し「不器用」だと思います。つまり、特定の人が関連している人のコレクションがありますが、「バックリレーション」もあります。
これは本当に必要ですか?このバックコレクションを削除し、代わりに PersonRepository にメソッドを指定して、特定の人物と何らかの関係を持つすべての人物を返すオプションはありませんか?

うーん、これは少しあいまいに聞こえるかもしれないので、ここにいくつかのコードがあります (簡潔にするために、「仮想」修飾子などを省略したことに注意してください... (私はこれらの修飾子を持たない方が好きなので、99ほとんどの場合、クラス マッピングで「lazy=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 クラスには 1 つのコレクションしか残っていません。これは、この Person が持つ関係を表す PersonPerson オブジェクトのコレクションです。特定の 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();

    }
}

「後方参照」は Person クラスのメンバーではありません。リポジトリ経由でアクセスする必要があります。これは、Eric Evans が彼の DDD - book で述べていることでもあります。場合によっては、関連オブジェクト (= 関連オブジェクト) を持ち歩くよりも、関連オブジェクトへのアクセスを提供できる特殊なメソッドをリポジトリに用意する方がよい場合があります。オブジェクト自体と。

私はコードをテストせず、ここに入力しただけなので、構文エラーなどもチェックしませんでした...しかし、これがどのように表示されるかについて少し明確にする必要があると思います.

于 2009-03-06T08:20:11.237 に答える