CakePHP中修改contain关联的JOIN条件问题咨询
解决全连接关联条件调整及数据获取问题
我来帮你搞定这个问题,分两种场景给你具体方案:
一、调整contain的关联条件(以CakePHP ORM为例)
如果你是用CakePHP的Containable行为,要把关联条件从Friends.animal2_id换成Friends.animal1_id,可以通过自定义关联配置来实现,不用纠结怎么改自动生成的SQL:
在模型中预定义不同的关联
比如在AnimalsTable里,除了默认关联,再单独定义一个基于animal1_id的关联:// src/Model/Table/AnimalsTable.php public function initialize(array $config): void { parent::initialize($config); // 默认关联(基于animal2_id) $this->hasMany('FriendsByAnimal2', [ 'className' => 'Friends', 'foreignKey' => 'animal2_id' ]); // 自定义关联(基于animal1_id) $this->hasMany('FriendsByAnimal1', [ 'className' => 'Friends', 'foreignKey' => 'animal1_id' ]); }查询时直接调用这个自定义关联即可:
$animals = $this->Animals->find() ->contain(['FriendsByAnimal1']) ->all();查询时动态覆盖关联条件
要是不想预定义模型关联,也可以在contain里直接指定参数:$animals = $this->Animals->find() ->contain([ 'Friends' => [ 'foreignKey' => 'animal1_id', // 这里直接替换成目标外键 'conditions' => [] // 有额外筛选条件可以加在这里 ] ]) ->all();
二、用JOIN实现全连接(解决仅获取单表数据的问题)
你说用join方法只能拿到一张表的数据,大概率是两个原因:要么JOIN类型不对(比如用了INNER JOIN而非全连接),要么没明确指定要查询的字段。
1. 数据库支持FULL OUTER JOIN的情况(比如PostgreSQL)
直接用全连接,指定关联条件为animal1_id,同时选中两张表的字段:
SELECT a.*, f.* FROM animals a FULL OUTER JOIN friends f ON a.id = f.animal1_id;
在ORM里(以CakePHP为例)可以这么写:
$query = $this->Animals->find() ->select(['Animals.*', 'Friends.*']) ->join([ 'table' => 'friends', 'alias' => 'Friends', 'type' => 'FULL', // 明确指定全连接类型 'conditions' => 'Animals.id = Friends.animal1_id' ]);
2. 数据库不支持FULL OUTER JOIN的情况(比如MySQL)
可以用UNION来模拟全连接:
-- 先拿左连接结果(动物表全量数据+匹配的friends数据) SELECT a.*, f.* FROM animals a LEFT JOIN friends f ON a.id = f.animal1_id UNION -- 再拿右连接结果(friends表全量数据+匹配的动物表数据,自动去重) SELECT a.*, f.* FROM animals a RIGHT JOIN friends f ON a.id = f.animal1_id;
ORM里可以通过合并两个查询实现:
$leftJoin = $this->Animals->find() ->select(['Animals.*', 'Friends.*']) ->leftJoinWith('Friends', function($q) { return $q->where(['Friends.animal1_id = Animals.id']); }); $rightJoin = $this->Friends->find() ->select(['Animals.*', 'Friends.*']) ->leftJoinWith('Animals', function($q) { return $q->where(['Animals.id = Friends.animal1_id']); }); $fullJoin = $leftJoin->unionAll($rightJoin);
这样就能拿到两张表的全连接数据,同时关联条件用的是animal1_id啦。
内容的提问来源于stack exchange,提问作者user7362769
相关产品推荐
相关产品推荐

