2009-03-03 33 views
5

Làm thế nào để ánh xạ một lớp đến các phiên bản khác của cùng một lớp khi mối quan hệ đó có các thuộc tính riêng là?Ánh xạ NHibernate khi các mối quan hệ tự tham gia có các thuộc tính bổ sung

Tôi có một lớp được gọi là Người được ánh xạ tới một Person bảng

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

Tôi muốn có một mối quan hệ nhiều-nhiều giữa người và người sử dụng một bảng tham gia gọi PersonPerson:

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

Tôi muốn các thuộc tính sau trong bảng PersonPerson:

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

This question và liên kết đến post by Billy McCafferty giải thích rằng mối quan hệ PersonPerson phải được đẩy từ một JOIN bình thường thành một thực thể theo đúng nghĩa của nó vì các cột bổ sung trong bảng PersonPerson. Tuy nhiên nó không giải thích những gì khi nó là một tự tham gia. Sự khác biệt là nếu tôi yêu cầu tất cả những người có liên quan đến số Dave Dee (ID = 1), tôi không chỉ nhận được Tich (ID = 5), nhưng tôi cũng nhận được Dozy (ID = 2) cũng vì Dave Dee cũng nằm trong cột RelatedPersonID.

Giải pháp của tôi cho đến nay, là có hai thuộc tính trong lớp Person của tôi.

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

Và có sau trong 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> 

Điều này có vẻ là một trifle clunky và thanh nha. NHibernate thường có các giải pháp thanh lịch cho hầu hết các vấn đề hàng ngày. Ở trên là cách hợp lý để làm điều này hoặc là có một cách tốt hơn?

Trả lời

2

Tôi nghĩ tôi cũng sẽ làm như vậy, nhưng, tôi nghĩ nó hơi 'vụng về' để mô hình hóa nó như thế này. Ý tôi là: bạn có một bộ sưu tập những người mà một người nào đó có liên quan, nhưng bạn cũng có 'mối quan hệ ngược'.
Điều này có thực sự cần thiết không? Nó không phải là một tùy chọn để loại bỏ bộ sưu tập này và thay vào đó, chỉ định một phương thức trên PersonRepository có thể cung cấp cho bạn tất cả những người có quan hệ với một người nào đó?

Hmm, điều này có thể có vẻ hơi mơ hồ, vì vậy đây là một số mã (lưu ý rằng vì lợi ích ngắn gọn, tôi đã bỏ các bộ sửa đổi 'ảo', v.v ... (tôi cũng không thích những bộ sửa đổi đó) , vì vậy trong 99% thời gian, tôi chỉ định 'lười biếng = false' ở đẳng cấp bản đồ của tôi).

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) 
    { 
     ... 
    } 

} 

Như bạn có thể thấy, lớp người chỉ có một bộ sưu tập còn lại, đó là một bộ sưu tập các PersonPerson Để có được những người có quan hệ với một người cụ thể, bạn có thể tạo một phương thức cụ thể trên PersonRepository của bạn trả về những người đó, thay vì có họ trong một bộ sưu tập trên lớp Person. Tôi nghĩ điều này cũng sẽ cải thiện hiệu suất.

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

    } 
} 

'Tham chiếu ngược' không phải là thành viên của lớp Người; nó phải được truy cập thông qua kho lưu trữ. Đây cũng là những gì Eric Evans nói trong cuốn sách DDD của ông: trong một số trường hợp, tốt hơn là nên có một phương pháp chuyên biệt trên kho lưu trữ có thể cung cấp cho bạn quyền truy cập vào các đối tượng liên quan, thay vì có chúng (= các đối tượng liên quan) xung quanh với chính đối tượng đó.

Tôi đã không kiểm tra mã, tôi chỉ cần gõ nó ở đây, vì vậy tôi cũng không kiểm tra lỗi cú pháp, vv ... nhưng tôi nghĩ rằng nó nên làm rõ một chút về cách tôi sẽ thấy điều này.

+0

@Frederik Gheysels Câu trả lời hay, tôi sẽ thử ngay bây giờ. Nó có vẻ là một giải pháp rõ ràng bây giờ mà bạn đã nói nó! –

+0

@Frederik - Tôi thích ý tưởng thực hiện điều này trong kho lưu trữ, nhưng nó vẫn chưa rõ ràng với tôi làm thế nào tôi sẽ lấy lại tất cả các trường hợp liên quan và các loại mối quan hệ là tốt. –

+0

Tôi sẽ trả về đối tượng Person có mối quan hệ với người được chỉ định. Offcourse, những đối tượng Person có bộ sưu tập 'PersonPerson' chứa tất cả các mối quan hệ mà Người này có. –

2

Dường như với tôi giống như bạn đã xây dựng mô hình của một directed graph và hai ánh xạ PersonPersonForwardPersonPersonBack đại diện cho các cạnh đi và đến tương ứng.

directedness này được củng cố bởi các ngữ nghĩa của các loại mối quan hệ của bạn: trong khi là-một-Đồng nghiệp-of rất có thể là một symmetric relation, là-một-đốc-oflà-một-Tutor-of hầu như không đối xứng.

Tôi nghĩ trong trường hợp này, mô hình dữ liệu đang cố gắng cho bạn biết rằng hai tập hợp các liên kết, trong khi loại tương thích, không giống nhau trong ngữ cảnh.

+0

Đây là những bảng hơi khó, nhưng tôi lấy ý kiến ​​của bạn. Tôi muốn các mối quan hệ đối xứng được đối xử giống như các mối quan hệ bất đối xứng. Điều đó không chỉ có nghĩa là những thứ đối xứng giống nhau theo cách nào? –

+0

Có, một cạnh vô hướng trong một đồ thị được định hướng khác sẽ được biểu diễn bằng một cặp cạnh được hướng, một hướng mỗi chiều. –

+0

Nếu bạn đang thực sự sau một biểu đồ lai, bán theo hướng, hãy thử tách mối quan hệ đối xứng thành bảng riêng của họ với ràng buộc kiểm tra (id bên trái <= right-id) để bình thường hóa và có lẽ là chế độ xem với trình tắt thích hợp được xác định thể hiện tính đối xứng liên quan. –

Các vấn đề liên quan