أفضل طريقة لنمذجة العلاقات المتعددة الأطراف في NHibernate عند التعامل مع قاعدة بيانات قديمة؟

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

  •  08-06-2019
  •  | 
  •  

سؤال

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

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

المحلول

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

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

انتبه إلى الطريقة التي تقوم بها الحقيبة بتخطيط جدول التفاصيل بشكل فعال في المجموعة.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.Customer, Namespace" table="Customer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="CustomerAccountId" length="4" sql-type="int" not-null="true" unique="true" index="CustomerPK"/>
            <generator class="native" />
        </id>

        <bag name="AcceptedOffers" inverse="false" lazy="false" cascade="all-delete-orphan" table="details">
          <key column="CustomerAccountId" foreign-key="AcceptedOfferFK"/>
          <many-to-many
            class="Namespace.AcceptedOffer, Namespace"
            column="AcceptedOfferFK"
            foreign-key="AcceptedOfferID"
            lazy="false"
           />
        </bag>

  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.AcceptedOffer, Namespace" table="AcceptedOffer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="AcceptedOfferId" length="4" sql-type="int" not-null="true" unique="true" index="AcceptedOfferPK"/>
            <generator class="native" />
        </id>

        <many-to-one 
          name="Plan"
          class="Namespace.Plan, Namespace"
          lazy="false"
          cascade="save-update"
        >
        <column name="PlanFK" length="4" sql-type="int" not-null="false"/>
        </many-to-one>

        <property name="StatusId" type="Int32">
            <column name="StatusId" length="4" sql-type="int" not-null="true"/>
        </property>

  </class>
</hibernate-mapping>

نصائح أخرى

لم أر مخطط قاعدة البيانات الخاص بك بينما كنت أكتب.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.Customer, Namespace" table="Customer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="customer_id" length="4" sql-type="int" not-null="true" unique="true" index="CustomerPK"/>
            <generator class="native" />
        </id>

        <bag name="AcceptedOffers" inverse="false" lazy="false" cascade="all-delete-orphan">
            <key column="accepted_offer_id"/>
            <one-to-many class="Namespace.AcceptedOffer, Namespace"/>
        </bag>

  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.AcceptedOffer, Namespace" table="Accepted_Offer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="accepted_offer_id" length="4" sql-type="int" not-null="true" unique="true" />
            <generator class="native" />
        </id>

        <many-to-one name="Plan" class="Namespace.Plan, Namespace" lazy="false" cascade="save-update">
            <column name="plan_id" length="4" sql-type="int" not-null="false"/>
        </many-to-one>

  </class>
</hibernate-mapping>

من المحتمل أن تقوم بالخدعة (لقد قمت فقط بعمل أمثلة لتعيينات المجموعات، وسيتعين عليك إضافة خصائص أخرى).

النهج الذي سأتبعه لتصميم هذا هو كما يلي:

يحتوي كائن العميل على ICollection <PaymentPlan> PaymentPlans التي تمثل الخطط التي قبلها العميل.

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

يحتوي كائن PaymentPlan على كائن PlanTerms الذي يمثل شروط خطة الدفع.

سيتم تعيين PlanTerms إلى PaymentPlan باستخدام تحديث حفظ متتالي لتعيين متعدد إلى واحد والذي سيؤدي فقط إلى إدراج مرجع إلى كائن PlanTerms ذي الصلة في PaymentPlan.

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

سينتهي بك الأمر بكائن العميل وكائن PaymentPlan وكائن PlanTerms مع امتلاك العميل (جدول العميل) لمثيلات PaymentPlans (جدول التفاصيل) والتي تلتزم جميعها بـ PlanTerms محددة (جدول الخطة).

لدي بعض الأمثلة الملموسة لبناء جملة التعيين إذا لزم الأمر ولكن ربما يكون من الأفضل العمل عليها باستخدام النموذج الخاص بك وليس لدي معلومات كافية عن جداول قاعدة البيانات لتقديم أي أمثلة محددة.

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

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

لا أعرف إذا كان هذا منطقيًا تمامًا، لكن اسمحوا لي أن أعرف وسأوضح أكثر.

أعتقد أن المشكلة التي تواجهك هنا هي أن كائن AcceptedOffer الخاص بك يحتوي على كائن Plan، ومن ثم يبدو أن كائن Plan الخاص بك يحتوي على مجموعة AcceptedOffers التي تحتوي على كائنات AcceptedOffer.نفس الشيء مع العملاء.أعتقد أن حقيقة أن الأشياء هي أبناء لبعضها البعض هو ما يسبب مشكلتك.

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

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

  1. قم بإنشاء كائن عرض منفصل ليس له حالة، على سبيل المثال، ليس لديه عميل وليس له حالة - فهو يحتوي فقط على معرف العرض والخطة التي ينتمي إليها كسماته.
  2. قم بتعديل كائن خطتك للحصول على مجموعة العروض (ليس من الضروري أن يكون العرض مقبولاً في سياقه).
  3. وأخيرًا، قم بتعديل كائن AcceptedOffer الخاص بك بحيث يحتوي على العرض والعميل والحالة.يبقى العميل هو نفسه.

أعتقد أن هذا سيؤدي بشكل كافٍ إلى فك تشابك تعيينات NHibernate ومشكلات حفظ الكائنات.:)

نصيحة قد تكون (أو لا) مفيدة في NHibernate:يمكنك تعيين الكائنات الخاصة بك مقابل طرق العرض كما لو كان العرض عبارة عن جدول.ما عليك سوى تحديد اسم العرض كاسم جدول؛طالما تم تضمين جميع الحقول NOT NULL في العرض وسيعمل التعيين بشكل جيد.

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