NeoEloquent 多对多关系指南:用 belongsToMany 构建好友与关注关系

📅 发布时间:2026/8/19 18:50:51
NeoEloquent 多对多关系指南:用 belongsToMany 构建好友与关注关系
NeoEloquent 多对多关系指南用 belongsToMany 构建好友与关注关系【免费下载链接】NeoEloquentThe Neo4j OGM for Laravel项目地址: https://gitcode.com/gh_mirrors/ne/NeoEloquentNeoEloquent 是 Laravel 生态中最流行的 Neo4j OGM对象图映射器它让 PHP 开发者可以用熟悉的 Eloquent 语法操作图数据库。而在所有关系类型中多对多关系belongsToMany最贴近真实世界的社交场景——好友、关注、点赞、收藏、标签全都离不开它。本文面向新手用关注关系和演员与电影两个例子带你彻底搞懂 NeoEloquent belongsToMany 的用法、核心方法attach / detach / sync以及关系属性Edge的高级技巧。为什么图数据库天然适合多对多关系在传统关系型数据库中多对多关系需要一张中间表来维护两个表之间的映射比如user_follow、post_tag。查询时要三次 JOIN稍不注意就性能堪忧。而 Neo4j 图数据库把关系本身当作一等公民——它是一条有方向、有类型、甚至可以携带属性的边Edge对比项关系型数据库Neo4j 图数据库关系载体中间表如 user_follow关系边如 :FOLLOWS关系属性需额外建表/字段直接挂在边上多跳查询多次 JOIN复杂度高一条 Cypher 搞定直观程度需要脑补所见即所得举个例子User A 关注 User B在图里就是一条(:User)-[:FOLLOWS]-(:User)的边关注时间、备注名这些属性直接存在边上即可。这就是 NeoEloquent 多对多关系的底层模型理解了它后面的 API 都顺理成章。快速上手用 belongsToMany 定义多对多关系以项目自带的电影示例Examples/Movies/models/为例一部电影有多个演员一个演员也演过多部电影这就是典型的多对多关系。在 Movie 模型中定义class Movie extends NeoEloquent { protected $fillable [title, year]; public function actors() { return $this-belongsToMany(Actor, ACTS_IN); } }第二个参数ACTS_IN就是关系类型在 Neo4j 中表现为边的类型。另一边Actor 模型里用hasMany定义反向关系class Actor extends NeoEloquent { protected $fillable [name]; public function movies() { return $this-hasMany(Movie, ACTS_IN); } }这样$movie-actors就能拿到所有演员$actor-movies就能拿到所有电影非常对称。你也可以参考项目自带的运行示例Examples/Movies/start.php跑起来看实际效果。构建关注关系attach 与查询完整流程 接下来实现本文的主角——关注 / 好友关系。在 NeoEloquent 官方文档中最简单的关注关系只需一个模型class User extends NeoEloquent { public function followers() { return $this-belongsToMany(User, FOLLOWS); } }第一步建立关注关系$jd关注$mc直接调用关系上的attach()方法可以传模型实例也可以传节点 ID$jd User::find(1012); $mc User::find(1013); // 方式一传模型实例 $jd-followers()-attach($mc); // 方式二传节点 ID $jd-followers()-attach(1013);生成的 Cypher 大致是MATCH (user:User), (followers:User) WHERE id(user) 1012 AND id(followers) 1013 CREATE (followers)-[:FOLLOWS]-(user)注意这里的方向$jd-followers返回的是指向 $jd 的入边集合语义正好是关注了我的人非常巧妙。第二步查询关注者$followers $jd-followers; // 谁关注了 $jd第三步实现互相关注$mc-followers()-attach($jd); // $mc 也关注 $jd 回去只改调用对象方向自动反转逻辑清晰到不需要注释。belongsToMany 核心方法速查表 多对多关系的增删改查集中在src/Eloquent/Relations/HasOneOrMany.php中实现下面是新手最常用的四个方法方法作用传参示例attach()建立关系节点已存在attach($mc)或attach([$id1, $id2])save()创建新节点并建立关系save(new Role([title Admin]))detach()解除关系detach($mc-id)sync()一键同步只保留指定集合sync([$id1, $id2, $id3])其中sync()是最省心的它会自动对比当前关系新增缺失的、移除多余的特别适合编辑用户的角色/标签这类场景$user-roles()-sync([$admin-id, $editor-id]);一次调用关系集合与目标集合完全一致。还可以为每个关系附加属性下文细讲$user-roles()-sync([ $master-id [type Master], $admin-id [type Admin], ]);给关系加属性利用 Neo4j 关系边Edge的妙用 ✨关系型数据库里关系上的信息如关注时间、备注往往无处安放而 Neo4j 的边可以携带属性NeoEloquent 将边封装成了Edge对象。看测试tests/functional/BelongsToManyRelationTest.php中testSyncingWithAttributes的用法$user-roles()-sync([ $master-id [type Master], $admin-id [type Admin], ]);之后每个边上就带上了type属性。想读取某两个模型之间的边用edge()方法$edge $user-roles()-edge($role); echo $edge-type; // 输出 Master需要批量操作关系时可以用edges()拿到所有边的集合边本身支持读写属性并save()持久化——你可以像操作模型一样操作关系。相关实现可查阅src/Eloquent/Relations/BelongsToMany.php。新手避坑指南 ⚠️根据官方测试用例这几个坑几乎人人都会踩1. attach 不存在的 ID 会抛异常。如果传入的 ID 在数据库中找不到对应节点会抛出ModelNotFoundException。所以 attach 前请确认节点存在。2. 删除关系 ≠ 删除节点。$user-roles()-delete()默认会连带删除另一端的节点如果只想断开关系、保留节点请传入true$user-roles()-delete(true); // 保留角色节点只删除关系3. 批量操作记得用集合。attach([$master, $admin, $editor])支持传入模型数组一次建立多条关系并返回 Edge 集合避免多次数据库往返。4. 关注关系方向别搞反。belongsToMany 默认是**入边in**方向即返回指向当前节点的关联模型如果你需要出边语义改用hasMany定义即可。方向相关实现见src/Eloquent/Edges/下的EdgeIn.php与EdgeOut.php。从哪里学习更多看测试源码最有效功能测试是理解 API 行为的最佳教材。关注/好友相关的完整测试集中在tests/functional/BelongsToManyRelationTest.php涵盖了批量 attach、批量 detach、sync 更新、带属性的 sync、懒加载、预加载eager loading、级联删除等全部场景。多对多关系的底层查询与匹配逻辑在src/Eloquent/Relations/BelongsToMany.php中配合src/Eloquent/Relations/HasOneOrMany.php阅读效果更佳。总结NeoEloquent 的 belongsToMany 把图数据库的多对多关系做到了开箱即用attach建立关系、detach解除关系、sync同步集合、Edge 让关系自带属性。无论是社交网络的关注体系还是内容平台的标签系统这套 API 都能优雅覆盖。动手写一个User::followers()试试看你会在五分钟内感受到图数据库的爽快。想要把玩完整源码可以执行git clone https://gitcode.com/gh_mirrors/ne/NeoEloquent仓库里自带电影示例Examples/Movies/和全套功能测试边读边跑进步最快。【免费下载链接】NeoEloquentThe Neo4j OGM for Laravel项目地址: https://gitcode.com/gh_mirrors/ne/NeoEloquent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考