需要帮助理解Doctrine中的多对多自引用代码

9

我正在努力理解来自Doctrine文档的这个代码块。

/** @Entity */
class User
{
    // ...

    /**
     * @ManyToMany(targetEntity="User", mappedBy="myFriends")
     */
    private $friendsWithMe;

    /**
     * @ManyToMany(targetEntity="User", inversedBy="friendsWithMe")
     * @JoinTable(name="friends",
     *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@JoinColumn(name="friend_user_id", referencedColumnName="id")}
     *      )
     */
    private $myFriends;

    // ...
}

以下是我如何解密一对多的双向关系 alt text
(来源: tumblr.com) 但如果我使用相同的方法,...下面是我得到的结果 alt text http://img514.imageshack.us/img514/2918/snagprogram0000.png 更新
我应该澄清我的问题。基本上,我不明白“myFriends”的反义词“friendsWithMe”是什么。我应该如何理解这段代码,更重要的是,如何编写这样的关系。
2个回答

12

我尝试回答我的问题,但我还是很困惑,希望有人能真正给出更好的答案。

所以首先回答关于如何派生$friendsWithMe的问题

基本上,我从“解码”一个更简单、更常见的多对多双向关系开始。

  • 1个用户可以属于多个群组
    • $user->groups
  • 1个群组可以有多个用户
    • $group->users

非常直接。但这在SQL中有什么意义呢?

alt text

实现代码

# select groups user is in
select group_id from users_groups
where user_id = 1

#select users of group
select user_id from users_groups
where group_id = 1

现在是关于在 SQL 中使用实际模型的部分...

alt text

代码中的部分

# select friends of given user
# $user->myFriends
select friend_id from friends
where user_id = 1;

# select users that are friends of given user
# $user->friendsWithMe
select user_id from friends
where friend_id = 1;

啊哈!选择给定用户的朋友用户,这就是我得到$friendsWithMe的方式。那么如何填充inversedBymappedBy和类的其余部分呢?

首先看看底部注释。

alt text

不清楚,需要深入思考,大概需要两天时间。

那么练习一下,如何从零开始创建一个自引用多对多关系?

我将要处理的示例...嗯,我认为很糟糕,但我会尝试 :) ...1个用户/学生可以有多个老师。1个老师可以有多个用户/学生。在这里,1个用户既可以是老师又可以是学生。就像在这样的论坛中,当你回答别人的问题时,你是老师,当你提问时,你是学生

ERD将如下所示

alt text

一些代码来选择教师学生和学生教师。

# select students of teacher
# $teacher->students
select student from teacher_student 
where teacher = 1;

# select teachers of student
# $student->teachers
select teacher from teacher_student
where student = 2;

好的,Doctrine 部分?

/** @Entity @Table(name="users")) */
class User {
    /**
     * @Id @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @Column(type="string", length="30")
     */
    private $name;
    /**
     * @ManyToMany(targetEntity="User", inversedBy="teachers")
     * @JoinTable(name="Teachers_Students",
     *              joinColumns={@JoinColumn(name="teacher", referencedColumnName="id")},
     *              inverseJoinColumns={@JoinColumn(name="student", referencedColumnName="id")}
     *              )
     */
    private $students;
    /**
     * @ManyToMany(targetEntity="User", mappedBy="students")
     */
    private $teachers;
}

这个为我生成表格的代码

# users
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

#teachers_students
CREATE TABLE `teachers_students` (
  `teacher` int(11) NOT NULL,
  `student` int(11) NOT NULL,
  PRIMARY KEY (`teacher`,`student`),
  KEY `student` (`student`),
  CONSTRAINT `teachers_students_ibfk_2` FOREIGN KEY (`student`) REFERENCES `users` (`id`),
  CONSTRAINT `teachers_students_ibfk_1` FOREIGN KEY (`teacher`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

最终我做到了!让我们测试一下...嗯,我遇到了问题。

致命错误:在D:\ResourceLibrary\Frameworks\Doctrine\tools\sandbox\index.php的第61行找不到类'Entities\User'

当我尝试执行某个操作时。

$user = new User;

zzz ...

我也在我的tumblr上写了关于这个问题的博客,并给出了我的解释。


+1 为了问题的清晰度和准备额外的资料所付出的努力。 - calumbrodie
1
你好。我在使用Doctrine时遇到了问题,涉及到关系。当我向这种集合添加项目、刷新并删除所有项目后再次刷新时,我会收到“在配置的命名空间中找不到类'Doctrine\ORM\Persisters\ManyToManyPersister'”的错误提示。但是,如果我删除项目但至少留下一个,则一切正常。你能否为我测试这种行为?如果你没有遇到任何问题,请告诉我你正在使用的Doctrine版本号?谢谢。 - Maciej Pyszyński

4
问题是,拥有M:N表:

  • friend_user_id
  • user_id

其中两个用户id为1和2。你只有:

friend_user_id = 1 and user_id = 2

还是两者都可以:

friend_user_id = 1 and user_id = 2 user_id = 2 and friend_user_id = 1

你可以实现这两种方式,这取决于你如何编写所拥有的一方集合的管理。

情况A:

public function addFriend(User $friend)
{
    $this->myFriends[] = $friend;
}

案例B:

public function addFriend(User $friend)
{
    $this->myFriends[] = $friend;
    $friend->myFriends[] = $this; // php allows to access private members of objects of the same type
}

关于你的新用户问题,你必须理解 PHP 5.3 命名空间的工作原理,首先你必须为 "Entities" 命名空间设置一个自动加载器,然后你还必须调用 "use Entities\User;" 来使用 "new User" 而不是 "new \Entities\User;"。 - beberlei
1
关于我的用户错误,事实证明我没有在类声明顶部放置namespace Entities - Jiew Meng
所以我可以说Case 1是单向关系,Case 2是双向关系?但是我认为,如果我是一个社交网络的用户,在这里每个人都可以成为朋友,我不会想成为某个人的朋友,仅仅因为他把我添加为好友。我已经测试了M:N关系,即使在自引用/双向设置中,当有人添加我为好友时,我也不会成为他的好友。似乎更多的是一种方便的方式,我可以找出谁是我的朋友。 - Jiew Meng
是的,有点像。在多对多自引用的情况下,关联和其中包含的数据都可以是单向或双向的。我同意这有点难以理解,但自引用的东西总是这样的 :-) - beberlei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接