【问题标题】:Bidirectional belongsToMany association on same model同一模型上的双向 belongsToMany 关联
【发布时间】:2015-10-06 14:53:48
【问题描述】:

这个EntitiesTable 与它自己有一个belongsToMany 关联:

class EntitiesTable extends AppTable
{
    public function initialize(array $config) {
        parent::initialize($config);
        
        $this->belongsTo('Users');
        $this->hasMany('Information');
        $this->belongsToMany('LinkedEntities', array(
            'className' => 'Entities',
            'through' => 'Links',
            'foreignKey' => 'from_id',
            'targetForeignKey' => 'to_id'
        ));
        $this->belongsToMany('Tags');
    }
}

但是,这种关联只在一个方向上起作用。当表links 只包含一个条目[from_id: 1, to_id: 2] 时,$this->Entities->findById(1)->contain('LinkedEntities') 正确获取链接实体,但$this->Entities->findById(2)->contain('LinkedEntities') 没有。

一种解决方案是复制表links 中的每个条目并交换from_idto_id,但这是不可取的。我更希望有一个 belongsToMany 关联,将from_id 视为foreignKey,将to_id 视为targetForeignKey,反之亦然。

如何实现双向的 belongsToMany 自关联?

一个例子

考虑以下类似图的网络:

每个点都有一个id,可能还有一些附加信息(如标题或坐标),并存储在entities 表中。

现在可以使用表格links来表示点之间的连接:

from_id     to_id
1           2
1           4
1           6
2           3
3           5
3           7
4           5
4           6
5           7

请注意,每个连接只存在一次,1-2 可以与 2-1 一样存储,从到到的方向无关紧要。

现在,如果我想让所有节点都连接到节点 1,我可以使用以下查询:

SELECT * FROM entities WHERE id IN (
    SELECT to_id FROM links WHERE from_id = 1
) OR id IN (
    SELECT from_id FROM links WHERE to_id = 1
)

看看这有多容易?我只需要确保检查两个方向,因为连接是双向的。

我想在 CakePHP 中映射这个关联。我知道这很可能目前是不可能的,这就是我打开issue in the CakePHP github 的原因。

【问题讨论】:

  • 相关问题:stackoverflow.com/q/20832098/2580794 该解决方案仅适用于旧版本的 CakePHP,因为选项 finderQuery 已删除。
  • 尝试通过 $id 查找 Entities,并将条件添加到可包含的 LinkedEntities WHERE is from_id = $id OR to_id = $id book.cakephp.org/3.0/en/orm/…
  • 添加附加条件只会进一步限制链接的实体,因为结果查询仍然需要 to_id 为 $id。
  • 我认为您需要创建两个关联:LinkedToEntities 和 LinkedFromEntities。
  • 也许foreignKeys 的命名有点糟糕。实际上,关联中没有 from 和 to,from_id 和 to_id 是可以互换的。除了 CakePHP 似乎无法处理这种情况外,一些链接实体没有任何逻辑理由处于一个或另一个关联中。

标签: cakephp orm cakephp-3.0 has-and-belongs-to-many bidirectional-relation


【解决方案1】:

这有帮助吗?

$this->belongsToMany('LinkedEntities', [
    'className' => 'Entities',
    'through' => 'links',
    'conditions' => [
         'OR' => [
                'AND' =>['Links.from_id = LinkedEntities.id', 'Links.to_id = Entities.id'],
                'AND' => ['Links.to_id = LinkedEntities.id', 'Links.from_id = Entities.id']
            ],
    ],
]);

把这个放在EntitiesTable里面

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多