9504


バージョンはCakePHP2.4.6です。  
DBはMySQLを使用しています。

異なるDB間でアソシエーションを組むにはどうしたらよいでしょうか？  
同一DB内で試すと正しい結果が取得できているのですが、  
異なるDBにすると望んだ結果が得られません。

DB・tableは下記のようになっています。

database.php

[code]

    public $default = array(
        'datasource' => 'Database/Mysql',
        'persistent' => false,
        'host' => '192.168.*.***',
        'login' => 'user',
        'password' => 'pass',
        'database' => 'customer_db',
        'prefix' => '',
        'encoding' => 'utf8',
    );
    public $company_db= array(
        'datasource' => 'Database/Mysql',
        'persistent' => false,
        'host' => '192.168.*.***',
        'login' => 'user',
        'password' => 'pass',
        'database' => 'company_db',
        'prefix' => '',
        'encoding' => 'utf8',
    );
    
[/code]

DB・Table構造

[code]

    DB：customer_db
    CREATE TABLE customer (
    　id INT NOT NULL AUTO_INCREMENT,
    　company_code INT NOT NULL,
    　customer_type varchar(255) NOT NULL,
    　PRIMARY KEY (`id`)
    )
    
    DB：company_db
    CREATE TABLE company (
    　id INT NOT NULL AUTO_INCREMENT,
    　company_code INT NOT NULL,
    　company_name varchar(255) NOT NULL,
    　PRIMARY KEY (`id`)
    )
    
    INSERT INTO customer (company_code, customer_type) VALUES
    (1, 'A'),
    (2, 'B'),
    (3, 'C');
    
    INSERT INTO company (company_code, company_name) VALUES
    (1, 'ああああ株式会社'),
    (2, '株式会社いいいい'),
    (3, 'うううう株式会社');
    
[/code]

これを下記のようにアソシエーションしています。

コントローラー

[code]

    <?php
    class CustomerController extends AppController {
    
      public $uses = array('Customer', 'Company');
    
        public function index() {
          $data = $this->Customer->find('all', array('limit' => 3));
          $this->set('customer', $data);
        }
    
    }
    
[/code]

モデル

[code]

    //Customer.php
    <?php
    
    class Customer extends AppModel {
    
      public $name = 'Customer';
      public $useDbConfig = "default";
      public $useTable = "customer";
    
      public $belongsTo = array(
          'Company' => array(
              'className' => 'Company',
              'fields' => array('company_code', 'company_name'),
              'conditions' => array('Customer.company_code = Company.company_code')
          )
      );
    }
    
    //Company.php
    <?php
    
    class Company extends AppModel {
    
      public $name = 'Company';
      public $useDbConfig = "company_db";
      public $useTable = "company";
    
    }
    
[/code]

これを実行すると下記のような結果が出力されます。

[code]

    array(
        (int) 0 => array(
            'Customer' => array(
                'id' => '1',
                'company_code' => '1',
                'customer_type' => 'A'
            ),
            'Company' => array(
                'company_code' => '1',
                'company_name' => 'ああああ株式会社'
            )
        ),
        (int) 1 => array(
            'Customer' => array(
                'id' => '2',
                'company_code' => '2',
                'customer_type' => 'B'
            ),
            'Company' => array(
                'company_code' => '1',
                'company_name' => 'ああああ株式会社'
            )
        ),
        (int) 2 => array(
            'Customer' => array(
                'id' => '3',
                'company_code' => '3',
                'customer_type' => 'C'
            ),
            'Company' => array(
                'company_code' => '1',
                'company_name' => 'ああああ株式会社'
            )
        )
    )
    
[/code]

Customer側は全データ正しく取得できているのですが、  
Company側が全て最初の1レコードしか取得できません。  
そこでSQLのログを確認したところ下記のようなSQL文が発行されていました。

[code]

    SELECT `Customer`.`id`, `Customer`.`company_code`, `Customer`.`customer_type` FROM `customer_db`.`customer` AS `Customer` WHERE 1 = 1 LIMIT 3
    SELECT `Company`.`company_code`, `Company`.`company_name` FROM `company_db`.`company` AS `Company` WHERE 1 = 1
    SELECT `Company`.`company_code`, `Company`.`company_name` FROM `company_db`.`company` AS `Company` WHERE 1 = 1
    SELECT `Company`.`company_code`, `Company`.`company_name` FROM `company_db`.`company` AS `Company` WHERE 1 = 1
    
[/code]

なぜJOINされないのかが調べてもわかりませんでした。  
2つのテーブルを同一DB内に置いた場合は正しくJOINされていました。  
異なるDB間でのJOINは不可能なのでしょうか？

よろしくお願い致します。


CC BY-SA 3.0
2015-04-20T09:07:08.277
9346
2015-04-23T05:36:32.780
9358
question
php cakephp
CakePHPで異なるDB間でアソシエーションを組む方法


異なるDBは別のデータソースと認識されるので、JOINできません。

この場合、リレーションを設定するのではなく、`Customer::afterFind()`を実装して、そこで`Company`モデルからデータを取得、紐付けします。

[code]

    public function afterFind($results, $primary = false) {
        $Company = ClassRegistry::init('Company');
        if (Hash::numeric(array_keys($results))) {
            // $results = [ 0 => ['Customer' => ...], 1 => ['Customer' => ...], ]
            $results = array_map(function ($record) use ($Company) {
                $conditions = [ /* 取得条件 */ ];
                $data = $Company->find('first', compact('conditions'));
                $record = Hash::merge($record, $data);
                return $record;
            }, $results);
        } else {
            // $results = ['Customer' => ...]
            $conditions = [ /* 取得条件 */ ];
            $data = $Company->find('first', compact('conditions'));
            $results = Hash::merge($results, $data);
        }
        return $results;
    }
    
[/code]

なお、このコードでは複数のCustomerが帰ってくる場合は、ひとつひとつCompanyを取得するのでかなり効率が悪いです。  
できれば、必要なCompanyを一括で取得した後に紐付けを行った方がよいかもしれません。


CC BY-SA 3.0
2015-04-23T05:36:32.780
9504
2015-04-23T05:36:32.780
2668
9346
answer