Yii2多对多关系迁移:如何像Laravel那样隐式创建中间表?
嘿,我来帮你梳理下Yii2里怎么实现Post与Comment的多对多关联~
Yii2中实现Post与Comment的多对多关联
首先得明确一点:Yii2不会像Laravel那样自动帮你生成comment_post中间表,你需要先手动创建这个表(或者用Yii2的迁移工具生成),然后在两个模型里定义关联关系。下面一步步来操作:
1. 先创建comment_post中间表
根据你给出的表结构,这个表包含id(主键)、post_id(关联post表id)、comment_id(关联comment表id)。如果用Yii2的迁移工具来创建,迁移代码大概是这样:
use yii\db\Migration; class m240520_123456_create_comment_post_table extends Migration { public function up() { $this->createTable('comment_post', [ 'id' => $this->primaryKey(), 'post_id' => $this->integer()->notNull(), 'comment_id' => $this->integer()->notNull(), ]); // 添加外键约束,保证关联数据的完整性 $this->addForeignKey( 'fk-comment_post-post_id', 'comment_post', 'post_id', 'post', 'id', 'CASCADE' ); $this->addForeignKey( 'fk-comment_post-comment_id', 'comment_post', 'comment_id', 'comment', 'id', 'CASCADE' ); } public function down() { // 先删外键再删表 $this->dropForeignKey('fk-comment_post-post_id', 'comment_post'); $this->dropForeignKey('fk-comment_post-comment_id', 'comment_post'); $this->dropTable('comment_post'); } }
执行迁移命令后,中间表就创建完成了。
2. 在Post模型中定义关联到Comment的关系
打开app\models\Post.php,添加一个getComments()方法来声明多对多关联:
use yii\db\ActiveQuery; use app\models\Comment; class Post extends \yii\db\ActiveRecord { // ... 其他原有代码 /** * 获取当前文章关联的所有评论 * @return ActiveQuery */ public function getComments() { return $this->hasMany(Comment::class, ['id' => 'comment_id']) ->viaTable('comment_post', ['post_id' => 'id']); } }
这里hasMany表示一个Post对应多个Comment,viaTable指定了中间表,第二个参数是字段映射规则:中间表的post_id对应Post模型的id,中间表的comment_id对应Comment模型的id。
3. 在Comment模型中定义关联到Post的关系
同样,打开app\models\Comment.php,添加getPosts()方法:
use yii\db\ActiveQuery; use app\models\Post; class Comment extends \yii\db\ActiveRecord { // ... 其他原有代码 /** * 获取当前评论关联的所有文章 * @return ActiveQuery */ public function getPosts() { return $this->hasMany(Post::class, ['id' => 'post_id']) ->viaTable('comment_post', ['comment_id' => 'id']); } }
4. 关联关系的使用
现在你就可以像Laravel那样便捷地使用关联了:
- 获取某篇文章的所有评论:
$post = Post::findOne(1); $comments = $post->comments; // 直接拿到关联的评论集合
- 获取某条评论关联的所有文章:
$comment = Comment::findOne(1); $posts = $comment->posts;
- 给文章关联评论(自动插入中间表记录):
$post = Post::findOne(1); $comment = Comment::findOne(2); $post->link('comments', $comment); // 这行代码会往comment_post表插入关联记录
- 取消评论与文章的关联:
$post->unlink('comments', $comment); // 删除中间表对应的关联记录
补充说明
如果你的中间表以后需要添加额外字段(比如关联创建时间),可以用via()方法关联一个中间表模型,这样就能操作中间表的额外字段了。不过你的场景里中间表只有主键和外键,用viaTable就完全足够啦。
内容的提问来源于stack exchange,提问作者Alex Lyashenko
相关产品推荐
相关产品推荐

