تعيينات nhibernate عندما يكون للعلاقات ذاتية التواصل خصائص إضافية

StackOverflow https://stackoverflow.com/questions/606330

سؤال

كيف تقوم بتخطيط فصل دراسي إلى مثيلات أخرى من نفس الفصل عندما يكون لهذه العلاقة خصائص نفسها?

لدي فصل يسمى الشخص الذي تم تعيينه إلى شخص طاولة

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

أريد السمات التالية في جدول الشخصيات:

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

هذا السؤال وربط إلى بعد بيلي ماكافيرتي يوضح أنه يجب ترقية علاقة الشخص من صلة طبيعية إلى كيان في حد ذاتها بسبب الأعمدة الإضافية في جدول الشخصيات. ومع ذلك ، فإنه لا يفسر ما عندما يكون التواصل الذاتي. الفرق هو أنه إذا طلبت من جميع الأشخاص ذوي الصلة ديف دي (معرف = 1) ، ليس فقط يجب أن أحصل عليها تيش (معرف = 5) ، لكن يجب أن أحصل أيضًا على ناعس (ID = 2) أيضًا لأن Dave Dee موجود أيضًا في العمود ذي الصلة.

ما هو الحل الخاص بي حتى الآن ، هو أن يكون لديك خصائصين في فصل شخصي.

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>

هذا يبدو trifle clunky و inelegant. عادة ما يكون لدى Nhibernate حلول أنيقة لمعظم المشكلات اليومية. هل المذكورة أعلاه هي الطريقة المعقولة للقيام بذلك أم أن هناك طريقة أفضل؟

هل كانت مفيدة؟

المحلول

أعتقد أنني سأفعل ذلك أيضًا ، لكنني أعتقد أنه من "الخرقاء" بعض الشيء أن يصممها مثل هذا. أعني: لديك مجموعة من الأشخاص يرتبط بهم شخص معين ، ولكن لديك أيضًا "علاقة خلفية".
هل هذا ضروري حقًا؟ أليس خيارًا لإزالة هذا التجميع الخلفي وبدلاً من ذلك ، حدد طريقة على 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 )
    {
       ...
    }

}

كما ترون ، فإن فئة الشخص لديها مجموعة واحدة فقط ، وهي مجموعة من الأشياء الشخصية التي تمثل العلاقات التي يتمتع بها هذا الشخص. من أجل الحصول على الأشخاص الذين لديهم علاقات مع شخص معين ، يمكنك إنشاء طريقة محددة على الشخص الشخصي الذي يعيد هؤلاء الأشخاص ، بدلاً من وجودهم في مجموعة على فئة الشخص. أعتقد أن هذا سيحسن الأداء أيضًا.

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

    }
}

"المرجع الخلفي" ليس عضوًا في فئة الشخص ؛ يجب الوصول إليه عبر المستودع. هذا أيضًا ما يقوله إريك إيفانز في كتابه - كتابه: في بعض الحالات ، من الأفضل أن يكون لديك طريقة متخصصة في المستودع يمكن أن تمنحك الوصول إلى الكائنات ذات الصلة ، بدلاً من وجودها (= الكائنات ذات الصلة) لتحملها مع الكائن نفسه.

لم أختبر الرمز ، لقد كتبته للتو هنا ، لذلك لم أتحقق أيضًا من خطأ بناء الجملة ، إلخ ... لكنني أعتقد أنه يجب أن يوضح قليلاً حول كيفية رؤية هذا.

نصائح أخرى

يبدو لي وكأنك بنيت بشكل أساسي نموذج أ مخطط موجه, ، والتعيينات PersonPersonForward و PersonPersonBack تمثل الحواف المنتهية ولايتها على التوالي.

يتم تعزيز هذا التوجيه من خلال دلالات أنواع علاقاتك: بينما IS-A-COLLEAGUE-OF على الأرجح أ علاقة متماثلة, IS-A-MANAGER-OF و IS-A-TUTOR هي بالتأكيد غير متماثلة.

أعتقد في هذه الحالة أن نموذج البيانات يحاول إخبارك أن مجموعتي الروابط ، في حين أن النوع المتوافق ، ليست هي نفس الشيء في السياق.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top