Laravel Eloquent:同时筛选父子表数据的教程

Laravel Eloquent:同时筛选父子表数据的教程

本教程详细阐述了如何在 laravel 中利用 eloquent orm 同时对父表和子表数据进行筛选。文章将深入探讨两种核心方法:使用 `join` 子句进行直接数据库连接,以及采用 `wherehas` 方法实现更具 eloquent 风格的关联查询。通过实际代码示例,您将学会如何根据父表的字段(如年份)和子表的字段(如标签id)构建高效且可读的过滤逻辑,并集成到控制器和视图中。

在 Laravel 应用开发中,我们经常需要处理具有一对多或多对多关系的数据。当用户需要根据父表和其关联子表的字段同时进行筛选时,如何高效地构建查询是关键。本教程将以 Post (父表) 和 PostTag (子表) 为例,演示如何实现这一需求,具体涉及根据 Post 表的 year 字段和 PostTag 表的 tag_id 字段进行过滤。

1. 模型及关系定义

首先,确保您的 Eloquent 模型已正确定义了它们之间的关系。在本例中,Post 模型与 PostTag 模型之间存在一对多关系。

Post.php

hasMany(PostTag::class);    }}

PostTag.php

belongsTo(Post::class);    }}

2. 视图中的筛选表单

用户通过一个包含年份和标签选择的表单来提交筛选请求。

View (movies/search_form.blade.php)

            @lang('movies.movie_all')        @if ($tags)            @foreach ($tags AS $tag)                id }}">{{ $tag->name }}            @endforeach        @endif                @lang('public.public_year')        @php            $currentYear = date('Y');            for ($i = $currentYear; $i > 1970; $i--) {                echo "".$i."";            }        @endphp        

3. 路由定义

定义一个 GET 路由来处理筛选请求。

web.php

Route::prefix('/movies')->group(function () {    Route::get('/search', [MovieController::class, 'MoviesDataSearch'])->name('movies.movie_search');});

4. 控制器中的筛选逻辑

在控制器中,我们将介绍两种实现父子表同时筛选的方法:使用 join 子句和使用 whereHas 方法。

4.1 方法一:使用 join 子句

join 子句允许您直接在数据库层面连接两个或多个表,然后对连接后的结果进行筛选。这种方法通常在需要高性能或需要直接访问连接表中所有列时非常有用。

优点:

性能通常较好,尤其是在处理大量数据时。可以直接在查询中访问所有连接表的列。

缺点:

如果不对 select 语句进行处理,可能会出现列名冲突。如果一个父记录有多个匹配的子记录,可能会导致父记录重复出现,需要使用 distinct() 或 groupBy() 来避免。

MovieController.php (使用 join)

where('posts.post_type', "movie")              ->where('posts.is_delete', "0");        // 如果存在标签筛选,则使用 join 连接 posts_tags 表        if ($request->filled('tag')) {            // 注意:'posts_tags.post_id' 是 PostTag 模型中指向 Post 模型的外键            $query->join('posts_tags', 'posts.id', '=', 'posts_tags.post_id')                  ->where('posts_tags.tag_id', $request->tag); // 假设 tag_id 是精确匹配            // 如果需要模糊匹配,可以使用 ->where('posts_tags.tag_id', 'like', '%'.$request->tag.'%');        }        // 如果存在年份筛选        if ($request->filled('year')) {            $query->where('posts.year', 'like', '%'.$request->year.'%');        }        // 避免因 join 导致重复的 Post 记录,并仅选择 Post 表的列        $movies = $query->select('posts.*')                        ->distinct() // 确保每个 Post 记录只出现一次                        ->orderBy('posts.id', 'DESC')                        ->paginate(12); // 分页大小可根据需求调整        // 保持筛选参数在分页链接中        return $movies->appends($request->all());    }}

注意事项:

join(‘posts_tags’, ‘posts.id’, ‘=’, ‘posts_tags.post_id’): 这里的 posts_tags.post_id 是 PostTag 表中关联 Post 表的外键。请根据您的实际数据库结构调整。select(‘posts.*’): 在使用 join 时,为了避免返回重复的列名或不必要的子表数据,通常建议明确指定要选择的列。distinct(): 如果一个 Post 记录有多个 PostTag 匹配筛选条件,join 可能会导致该 Post 记录在结果集中出现多次。distinct() 可以确保每个 Post 记录只返回一次。

4.2 方法二:使用 whereHas 方法

whereHas 是 Eloquent 提供的一种更高级、更具对象化风格的方法,用于根据关联模型的条件来筛选父模型。它会在底层生成一个 EXISTS 子查询。

优点:

代码更简洁,更符合 Eloquent 的设计理念。自动处理连接逻辑,无需手动指定 join 条件。避免了 join 可能导致的重复父记录问题。

缺点:

对于非常复杂的关联查询或需要高度优化性能的场景,有时 join 可能更直接高效。无法直接选择关联模型的列。

MovieController.php (使用 whereHas)

where('post_type', "movie")              ->where('is_delete', "0");        // 如果存在年份筛选        if ($request->filled('year')) {            $query->where('year', 'like', '%'.$request->year.'%');        }        // 如果存在标签筛选,则使用 whereHas        if ($request->filled('tag')) {            $query->whereHas('PostTags', function ($q) use ($request) {                // 在关联模型 PostTag 上应用筛选条件                $q->where('tag_id', $request->tag); // 假设 tag_id 是精确匹配                // 如果需要模糊匹配,可以使用 $q->where('tag_id', 'like', '%'.$request->tag.'%');            });        }        $movies = $query->orderBy('id', 'DESC')                        ->paginate(12);        // 保持筛选参数在分页链接中        return $movies->appends($request->all());    }}

注意事项:

whereHas(‘PostTags’, function ($q) use ($request) { … }): PostTags 是在 Post 模型中定义的关系方法名。闭包函数 $q 代表了对 PostTag 模型进行的查询。$request->filled(‘year’) 和 $request->filled(‘tag’): 使用 filled() 方法可以检查请求参数是否存在且非空,这有助于构建更健壮的条件查询。

5. 总结与最佳实践

选择方法:如果您需要直接从关联表中选择列,或者对性能有极高要求且熟悉 SQL JOIN 语句的优化,join 方法可能更适合。如果您追求代码的 Eloquent 风格、可读性,并且主要目的是根据关联条件筛选父模型,那么 whereHas 是更推荐的选择。它通常能满足大部分业务需求,并且更不容易引入重复记录的问题。条件查询: 在控制器中,使用 if ($request->filled(‘param’)) 或 Eloquent 的 when() 方法来根据请求参数的有无动态构建查询条件,可以使代码更加灵活和健壮。

// 使用 when() 的示例$movies = Post::where('post_type', "movie")    ->where('is_delete', "0")    ->when($request->filled('year'), function ($query) use ($request) {        return $query->where('year', 'like', '%'.$request->year.'%');    })    ->when($request->filled('tag'), function ($query) use ($request) {        return $query->whereHas('PostTags', function ($q) use ($request) {            $q->where('tag_id', $request->tag);        });    })    ->orderBy('id', 'DESC')    ->paginate(12);

分页链接: 务必使用 $movies->appends($request->all()) 来确保在分页时,所有当前的筛选参数都能被保留,从而提供更好的用户体验。外键匹配: 无论是 join 还是 whereHas,都依赖于正确的外键关系。请确保您的数据库表和 Eloquent 模型中的外键定义是准确无误的。输入验证: 在实际应用中,始终对用户输入进行验证(例如,使用 Laravel 的表单请求验证),以防止恶意数据或不符合预期的数据影响查询。

通过掌握 join 和 whereHas 这两种强大的 Eloquent 查询方法,您将能够灵活高效地处理 Laravel 中父子表数据的复杂筛选需求。

以上就是Laravel Eloquent:同时筛选父子表数据的教程的详细内容,更多请关注php中文网其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1338941.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Laravel Dusk:通过 DevTools 协议管理浏览器权限
上一篇 2025年12月13日 02:30:30
PHP中解析和遍历GeoJSON多边形坐标数据
下一篇 2025年12月13日 02:30:39

相关推荐

  • 百家号动态怎么发布_百家号动态发布的方法与注意事项

    百家号动态怎么发布_百家号动态发布的方法与注意事项百家号动态怎么发布_百家号动态发布的方法与注意事项百家号动态怎么发布_百家号动态发布的方法与注意事项百家号动态怎么发布_百家号动态发布的方法与注意事项

    要成功发布百家号动态,需先完成账号注册与实名认证,确保具备发布权限。通过手机APP或网页后台进入发布页面,撰写200字内简洁内容,可添加9张图或短视频及话题标签以提升推荐。发布前须遵守审核规则:禁发政治敏感、虚假宣传、侵权盗用、低质标题党及夸大医疗效果等内容,避免审核失败或账号限流,保障内容合规与曝…

    2026年9月26日 • 用户投稿
    100
  • Laravel框架中Pipeline的解析(代码示例)

    本篇文章给大家带来的内容是关于laravel框架中pipeline的解析(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 大家好,今天给大家介绍下Laravel框架的Pipeline。 它是一个非常好用的组件,能够使代码的结构非常清晰。 Laravel的中间件机制便是基于…

    2026年9月26日
    000
  • 云原生Java监控全套方案:从Micrometer到Grafana可视化看板

    云原生Java监控全套方案:从Micrometer到Grafana可视化看板云原生Java监控全套方案:从Micrometer到Grafana可视化看板云原生Java监控全套方案:从Micrometer到Grafana可视化看板云原生Java监控全套方案:从Micrometer到Grafana可视化看板

    云原生Java监控方案以Micrometer收集指标,Prometheus存储查询,Grafana实现可视化。Micrometer提供供应商中立的API,与Spring Boot Actuator集成,自动暴露JVM、HTTP等指标;通过micrometer-registry-prometheus依…

    2026年9月26日 • 用户投稿
    000
  • Laravel Eloquent的技巧分享(示例讲解)

    本篇文章给大家带来的内容是关于laravel eloquent的技巧分享(示例讲解),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 Laravel 是一个功能丰富的框架。但是,你无法从官方文档中找到所有可用的功能。以下是一些你可能不知道的功能。 1.获取原始属性 当修改一条 Elo…

    2026年9月26日
    000
  • 百度极速版如何查看历史记录_百度极速版浏览历史的查找方法

    百度极速版如何查看历史记录_百度极速版浏览历史的查找方法百度极速版如何查看历史记录_百度极速版浏览历史的查找方法百度极速版如何查看历史记录_百度极速版浏览历史的查找方法百度极速版如何查看历史记录_百度极速版浏览历史的查找方法

    打开百度极速版APP,点击底部“我的”进入个人中心;2. 点击“历史”查看阅读浏览记录;3. 切换至“搜索浏览”查看搜索记录;4. 若无记录需检查设置中历史记录功能是否开启。 在百度极速版里查看历史记录很简单,主要通过“我的”页面进入。下面介绍具体查找方法。 如何进入历史记录页面 打开手机上的百度极…

    2026年9月26日 • 用户投稿
    200
  • 服务发现组件 Eureka 和 Nacos 有什么区别?

    服务发现组件 Eureka 和 Nacos 有什么区别?服务发现组件 Eureka 和 Nacos 有什么区别?服务发现组件 Eureka 和 Nacos 有什么区别?服务发现组件 Eureka 和 Nacos 有什么区别?

    Eureka 侧重服务注册与发现,适合简单场景;Nacos 功能更全,支持配置管理、动态更新与高扩展性,适用于复杂微服务架构。选择需根据技术栈、项目规模及未来扩展需求权衡,Nacos 在大型项目中更具优势。 Eureka 和 Nacos 都是服务发现组件,核心作用都是让服务能够被其他服务找到并调用。…

    2026年9月26日 • 用户投稿
    000
  • laravel项目之发布导致的BUG(环境变量问题)

    本篇文章给大家带来的内容是关于laravel项目之发布导致的BUG(环境变量问题) ,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 laravel项目的某一次发布后,项目中连接数据库突然报错,而用同样的数据库账号密码在机器上连接是可以的。 临时解决方案 经过短暂时间的排查,没找到原…

    2026年9月26日
    300
  • 实现搜索结果按字母排序:PHP结合Ajax的专业教程

    本文档旨在提供一种使用PHP和Ajax对通过POST方法获取的搜索结果进行A-Z排序的解决方案。我们将创建一个表单,保存POST数据,并利用PHP函数对医生列表进行排序,最终通过Ajax实现无需刷新页面的排序功能。 1. 修改 search.php 文件 首先,我们需要在 search.php 文件…

    2026年9月26日
    000
  • 网易云音乐网页版在线播放网址 网易云音乐网页版官网登录入口

    网易云音乐网页版官网登录入口为https://music.163.com/,支持在线播放、MV搜索、歌单管理、电台收听及内容收藏分享等功能,界面简洁,适配多设备,涵盖新碟、榜单、独立音乐人及场景化音频内容。 网易云音乐网页版在线播放网址在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来网易云…

    2026年9月26日
    000
  • 一篇文章带你深入了解Flink SQL流处理中的特殊概念

    一篇文章带你深入了解Flink SQL流处理中的特殊概念一篇文章带你深入了解Flink SQL流处理中的特殊概念一篇文章带你深入了解Flink SQL流处理中的特殊概念一篇文章带你深入了解Flink SQL流处理中的特殊概念

    本文深入探讨了flink sql流处理中的特殊概念,主要包括表与流处理的区别、动态表的概念以及流式持续查询的过程。以下是详细介绍。 一、流处理和关系代数(表,及 SQL)的区别 可以看出,关系代数(主要指关系型数据库中的表)和 SQL 主要针对批处理,这与流处理存在天然的差异。 二、动态表(Dyna…

    2026年9月26日 • 用户投稿
    100
  • laravel任务调度的介绍(附代码)

    本篇文章给大家带来的内容是关于laravel任务调度的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 导语:之前写过使用 Linux 的进行定时任务,实际上 laravel 也可以执行定时任务。需求是统计每日访问的 IP 数,虽然数据表中有数据,为了演示,新建监听器统…

    2026年9月26日
    700
  • QQ好友动态无法查看怎么办

    QQ好友动态无法查看怎么办QQ好友动态无法查看怎么办QQ好友动态无法查看怎么办QQ好友动态无法查看怎么办

    首先检查好友动态权限,确认是否被限制访问;再核实自身账号状态,排除被拉黑可能;接着清除QQ缓存并更新至最新版本;最后尝试切换网络或使用网页端查看。 QQ好友动态无法查看,通常和权限设置、网络问题或软件异常有关。先别着急,可以按以下方法逐一排查解决。 检查好友的动态权限设置 有些好友设置了动态访问权限…

    2026年9月26日 • 用户投稿
    000
  • 基于Quarkus的云原生Java开发:启动时间低于0.5秒的实践方案

    基于Quarkus的云原生Java开发:启动时间低于0.5秒的实践方案基于Quarkus的云原生Java开发:启动时间低于0.5秒的实践方案基于Quarkus的云原生Java开发:启动时间低于0.5秒的实践方案基于Quarkus的云原生Java开发:启动时间低于0.5秒的实践方案

    Quarkus通过GraalVM Native Image预编译实现启动时间低于0.5秒,需配置pom.xml插件、优化依赖、使用Quarkus CLI并监控调优。 Quarkus通过预编译和GraalVM Native Image等技术,让Java应用在云原生环境中拥有极低的启动时间和内存占用。本…

    2026年9月26日 • 用户投稿
    500
  • laravel使用Faker数据填充的方法介绍(代码)

    laravel使用Faker数据填充的方法介绍(代码)laravel使用Faker数据填充的方法介绍(代码)laravel使用Faker数据填充的方法介绍(代码)laravel使用Faker数据填充的方法介绍(代码)

    本篇文章给大家带来的内容是关于laravel使用Faker数据填充的方法介绍(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 导语:做开发的时候,添加测试数据是必不可少的,laravel 内置了很方便的数据填充,下面是实例。 数据迁移 先创建数据模型和数据迁移 php art…

    2026年9月26日 • 用户投稿
    000
  • JavaAI实战:基于DeepLearning4j实现目标检测模型部署

    JavaAI实战:基于DeepLearning4j实现目标检测模型部署JavaAI实战:基于DeepLearning4j实现目标检测模型部署JavaAI实战:基于DeepLearning4j实现目标检测模型部署JavaAI实战:基于DeepLearning4j实现目标检测模型部署

    答案:在Java中通过DeepLearning4j部署目标检测模型需完成模型转换、数据预处理、推理执行和结果解析。首先利用KerasModelImport或ONNX将TensorFlow/Keras模型转为DL4J兼容格式,注意版本匹配与层兼容性;接着通过NativeImageLoader加载图像并…

    2026年9月26日 • 用户投稿
    600
  • vivo浏览器如何设置电脑版UA_vivo浏览器切换电脑版网页标识方法

    vivo浏览器如何设置电脑版UA_vivo浏览器切换电脑版网页标识方法vivo浏览器如何设置电脑版UA_vivo浏览器切换电脑版网页标识方法vivo浏览器如何设置电脑版UA_vivo浏览器切换电脑版网页标识方法vivo浏览器如何设置电脑版UA_vivo浏览器切换电脑版网页标识方法

    可通过修改用户代理(UA)标识使vivo浏览器访问电脑版网页。首先尝试在设置中将UA标识切换为“Desktop”模式;若不支持,可手动输入电脑版UA字符串;还可安装UA切换插件实现一键切换,刷新页面后即可加载桌面版网站内容。 如果您在使用vivo浏览器时希望访问电脑版网页,但页面自动跳转至移动版,可…

    2026年9月26日 • 用户投稿
    400
  • 小红书动态无法点赞怎么办

    小红书动态无法点赞怎么办小红书动态无法点赞怎么办小红书动态无法点赞怎么办小红书动态无法点赞怎么办

    先检查账号状态、网络环境及客户端问题。确认账号无违规、笔记可推广,避免异常操作;刷新登录、切换网络、清缓存、更新App;换设备测试排除风控,禁用多开软件;若均无效,联系客服解决。 小红书动态无法点赞,通常由账号状态、网络环境或客户端问题引起。可以按以下步骤逐一排查解决。 检查账号与内容状态 账号或发…

    2026年9月26日 • 用户投稿
    500
  • Firefox浏览器电脑版下载 火狐手机版官方安装包

    Firefox浏览器电脑版下载 火狐手机版官方安装包Firefox浏览器电脑版下载 火狐手机版官方安装包Firefox浏览器电脑版下载 火狐手机版官方安装包Firefox浏览器电脑版下载 火狐手机版官方安装包

    Firefox浏览器官方下载地址为https://www.mozilla.org/zh-CN/firefox/new/,提供电脑版与手机版安装包;其核心功能包括标签式浏览、弹出窗口拦截、追踪器屏蔽、跨设备数据同步及密码加密存储等。 Firefox浏览器电脑版下载、火狐手机版官方安装包在哪里?这是不少…

    2026年9月26日 • 用户投稿
    200
  • 一键PHP环境可以同时跑多个PHP版本吗_多版本共存实现

    多PHP版本共存可行。通过宝塔、phpStudy等集成环境或手动配置Nginx+多PHP-FPM,可实现不同站点使用不同PHP版本,需注意扩展兼容性、端口冲突及安全维护。 一键PHP环境通常指的是集成化的开发环境工具,比如 XAMPP、WAMP、宝塔面板 或 phpStudy 这类软件。这类工具默认…

    2026年9月26日
    100
  • Google浏览器官网入口一键直达

    Google浏览器官网入口一键直达Google浏览器官网入口一键直达Google浏览器官网入口一键直达Google浏览器官网入口一键直达

    Google浏览器官网入口一键直达地址是https://www.google.cn/chrome/,该网址提供简洁界面、多标签管理、智能搜索、网页翻译等功能,并支持跨设备同步书签、历史记录和密码,具备高效性能与安全更新。 Google浏览器官网入口一键直达在哪里?这是不少网友都关注的,接下来由PHP…

    2026年9月26日 • 用户投稿
    100

发表回复

登录后才能评论
关注微信