【问题标题】:Reflexive many-to-many relationship in CakePHPCakePHP 中的自反多对多关系
【发布时间】:2013-05-04 03:53:27
【问题描述】:

我一直在寻找这个问题的明确答案,但一直无法解决。我最近一直在使用(和学习)CakePHP,并且遇到了障碍。为了简化我的数据库,假设我们只有两个表:

persons relationships(或persons_persons

Persons 与自身之间存在多对多关系 - 事实上,两个人之间可以存在不止一种关系:

persons
-------
*person_id*
name

relationships
-------------
*relationship_id*
person_1_id
person_2_id
start_date
end_date

现在,如果我想说 Person1 (id=1) 与 Person2 结婚,我将在 relationships 表中有一个条目。 person_1_id 将是 1person_2_id 将是两个。

我可以在 CakePHP 中创建这种关系,并显示每个 Person 记录的关系(和人员)列表。但是,这是一个单向关系:对于 Person 1,查询只会拉取 person_1_id 匹配的 Relationship 对象。如果我想查询第 2 个人的关系,我必须有第二个相同的行,将 person_1_idperson_2_id 交换。

这是模型:

class Member extends AppModel {
    public $hasMany = array(
        'Relationships' => array(
            'className' => 'Relationship',
            'foreignKey' => 'person_1_id'
        )
    );
}

class Relationship extends AppModel {
    public $belongsTo = array(
        'Person1' => array(
            'className' => 'Person',
            'foreignKey' => 'person_1_id'
        ),
        'Person2' => array(
            'className' => 'Person',
            'foreignKey' => 'person_2_id'
        )
    );
}

有什么建议吗?当 person_1_id 实际上与 person_2_id 没有分离时,复制关系实体没有逻辑意义。

【问题讨论】:

    标签: php cakephp


    【解决方案1】:

    我认为你有两个选择:

    1。复制关系记录

    换个角度看;考虑directedun-directed 图的概念。您当前的模式支持离开一个对象(人)并到达另一个对象的有向边。从您的应用程序的角度来看,一个人不能在他们不知情的情况下与另一个人建立关系。

    如果您确实选择了这条路线,那么数据库中的空间量可以忽略不计,并且实现起来比选项 2 更简单。请记住,您应该采取措施确保关系在任何时候。

    2。处理应用程序中的关系不对称

    创建另一个关系,使您的模型如下所示:

    class Member extends AppModel {
        public $hasMany = array(
            'RelationshipsA' => array(
                'className' => 'Relationship',
                'foreignKey' => 'person_1_id'
            ),
            'RelationshipsB' => array(
                'className' => 'Relationship',
                'foreignKey' => 'person_2_id'
            )
        );
    }
    

    然后,根据您的人存在于关系的哪一边,您可以为您的关系设置单独的箱子。然后,您必须在任何地方放置额外的逻辑,以便您可以将关系箱作为一个同质集合来处理。

    很抱歉,我无法再提供帮助了,但我想不通,如何实现一个无向图而不在有向图之上构建它。

    2013 年 5 月 5 日更新

    总结评论线程,在hasMany 关联上设置finderQuery 可以掩盖重复查找与person_2_id (Documentation) 的关联的需要:

    'Relationship' => array(
        'finderQuery' => 'SELECT Relationship.* FROM relationships AS Relationship WHERE Relationship.person_2_id = {$__cakeID__$} OR Relationship.person_1_id = {$__cakeID__$};'
    )
    

    这隐藏了复杂的检索机制,但存储关系可能需要进一步考虑。

    【讨论】:

    • 感谢山姆的深思熟虑的回应。这些基本上是我一直在自己身边折腾的两个选择。我的部分保留是我可以在不使用 ORM 的情况下轻松地做到这一点 - 连接将是任一键上的 OR,我正在尝试弄清楚如何在这里应用它。我尝试了 hasMany 关系的finderQuery,但没有运气。现在,我不会回答这个问题,但我最终可能会选择选项 #1。
    • 不用担心@AnthonyAziz,我很高兴能为您的困境提供一点帮助。当您说 finderQuery 时,您的意思是 $this->Model->query('...')
    • 在 hasMany 关系中,finderQuery 应该是一种指定自定义查询的方法——想法来自这篇文章:visuallizard.com/blog/2009/02/19/210
    • 在玩了这个之后,Sam,我能够让它与查找器查询一起工作 - 问题是我的 hasMany 关联被命名为“Relationships”并且 SQL 查询的表别名为“关系”。显然这是个问题?无论如何,我将此标记为答案,或者是为了您的有用提示,或者因为我最终可能会采用具有重复/反向关系的定向设计。再次感谢您的帮助!
    • 谢谢@AnthonyAziz,我已经在答案的更新中总结了我们的讨论,以便对其他人有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多