العمل مع النماذج التي لا تحتوي على مفتاح خارجي واحد في CakePHP

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

سؤال

أنا أعمل على تطبيق يحتوي على بيانات مستوردة من مصدر أجنبي (وغير قابل للتغيير تمامًا).سأقوم بتبسيط بعض الجداول لتوضيح المشكلة.فيما يلي الجداول مع مفاتيحها الأساسية.

invoices     (doc_number, date_printed, batch_number)
headers      (doc_number, date_printed, batch_number)
deliveries   (doc_number, date_printed, batch_number)
transactions (doc_number, date_printed, batch_number, line_number)
messages     (doc_number, date_printed, batch_number, line_number)

لذلك يمكنك أن ترى أن الفواتير والترويسات والتسليمات لها علاقات رأس برأس.تعتبر الفواتير إلى المعاملات والفواتير إلى الرسائل من واحد إلى متعدد.

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

تكمن المشكلة الآن في إعداد العلاقات في Cake، نظرًا لأنه لا يتعامل مع المفاتيح المركبة على الإطلاق.لقد تمكنت من جعل العلاقات الفردية تعمل على النحو التالي:

class Invoice extends AppModel {
    public $name = "Invoice"
         , $hasOne = array(
            "Header" => array(
                'foreignKey' => false,
                'conditions' => array(
                    "Invoice.doc_number = Header.doc_number",
                    "Invoice.date_printed = Header.date_printed",
                    "Invoice.batch_number = Header.batch_number"
                )
            )
         )
    ;
}

وهذا ينجح، لأنه يتم الاستعلام عن علاقات رأس برأس دفعة واحدة باستخدام LEFT JOIN كبيرة.تنتهي تجربة نفس الطريقة مع علاقة رأس بأطراف (على سبيل المثال، مع الفواتير والمعاملات)، لأن Cake يقوم باستعلامين:الأول للعثور على جميع الفواتير المطابقة، ثم الثاني للعثور على جميع المعاملات ذات المفتاح الخارجي المقابل الذي يطابق نتائج الاستعلام الأول:(هذا هو الاستعلام المبسط الذي يحاول تشغيله)

SELECT `Transaction`.* FROM `transactions` AS `Transaction`
WHERE `Invoice`.`doc_number` = `Transaction`.`doc_number`
AND `Invoice`.`date_printed` = `Transaction`.`date_printed`
AND `Invoice`.`batch_number` = `Transaction`.`batch_number`

كما ترى، لا يتم ضمها إلى الفواتير، لذا ينتهي الاستعلام.

أي أفكار حول كيف يمكنني جعل هذا العمل؟

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

المحلول

أسوأ سيناريو، يمكنك استخدام معلمة finderQuery الخاصة بـ لديه علاقة كثيرة.انها تسمح لك لتجاوز الاستعلامات تماما.

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

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

<?php
class Invoice extends AppModel() {
    ...

    function getInvoice($conditions) {
        $invoice = $this->find('first', compact('conditions'));

        $conditions = array(
             'Transaction.doc_number' => $invoice['Invoice']['doc_number'],
             'Transaction.date_printed' => $invoice['Invoice']['date_printed'],
             'Transaction.batch_number' => $invoice['Invoice']['batch_number']);
        $invoice['transactions'] = $this->Transaction->find('all', compact('conditions'));

        return $invoice;
    }
}
?>

إذا كنت تستخدم وظيفة مثل تلك الموجودة في النموذج، فلا تنس أن الفاتورة ستحتاج إلى علاقة محددة بالمعاملة، حتى لو لم تستخدمها مباشرة، بحيث يتم تعريف $this->Transaction.

وأيضًا، إذا كنت تفضل إرجاع البيانات بالطريقة التي ستكون بها العلاقة hasMany، فيمكنك دائمًا إضافة حلقة foreach لإعادة تجميعها بهذه الطريقة.

تحديثهناك أيضا سلوك SimpleResults في مخبز الكيك من شأنه أن يسمح بإرجاع تلك النتائج بسهولة من الجدول الآخر بتنسيق ارتباط hasMany العادي.

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