You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent关联软删除数据查询无结果问题及解决方法

问题分析与解决方案:Eloquent关联查询无返回数据但all()可获取结果

首先,咱们来拆解下你遇到的问题:你写的关联查询没返回任何数据,但Medidore::all()能拿到包含软删除的所有记录,核心原因大概率出在内连接的过滤逻辑或者关联表的软删除处理上,下面一步步给你分析和解决:

可能的原因

  • 内连接(join)的过滤特性:Eloquent的join是内连接,只有当关联表中存在完全匹配的记录时,才会返回结果。如果你的medidores表中有记录的关联ID(比如empresa_id、cod_tipo_medidor等)在对应的关联表中找不到匹配项,或者canal2字段为null,这些记录都会被内连接过滤掉。
  • 关联表的软删除未处理:如果你的关联表(比如empresas、tipo_medidor)也使用了软删除(有deleted_at字段),但你的查询没有排除这些表中已软删除的记录,可能导致连接条件不匹配。
  • 字段名或关联关系错误:比如拼写错误(比如cod_tipo_medidor是不是应该是tipo_medidor_id?),或者关联的ID字段类型不匹配(比如一个是字符串,一个是整数)。

排查与解决步骤

1. 先查看生成的SQL语句,定位问题

把你的查询改成输出SQL,直接在数据库里执行,就能清楚看到哪里出问题了:

// 构建查询但不执行
$query = Medidore::select([ 
    'medidores.*', 
    'empresas.name as empresa', 
    'tipo_medidor.descripcion as tipomedidor', 
    'tipo1.descripcion as canal_1', 
    'tipo2.descripcion as canal_2'
])
->join('empresas', 'medidores.empresa_id', '=', 'empresas.id')
->join('tipo_medidor', 'medidores.cod_tipo_medidor', '=', 'tipo_medidor.id')
->join('tipo_canal_med as tipo1', 'medidores.canal1', '=', 'tipo1.id')
->join('tipo_canal_med as tipo2', 'medidores.canal2', '=', 'tipo2.id')
->whereNull('medidores.deleted_at');

// 输出生成的SQL
echo $query->toSql();

把输出的SQL复制到数据库管理工具(比如phpMyAdmin、Navicat)里执行,看看是否真的没有结果,或者哪里的条件导致了过滤。

2. 改用左连接保留所有未软删除的medidores记录

如果是内连接过滤掉了部分关联不完整的记录,把join改成leftJoin(左连接),这样即使关联表没有匹配项,也会返回medidores的记录,关联字段会显示为null:

$datos = Medidore::select([ 
    'medidores.*', 
    'empresas.name as empresa', 
    'tipo_medidor.descripcion as tipomedidor', 
    'tipo1.descripcion as canal_1', 
    'tipo2.descripcion as canal_2'
])
->leftJoin('empresas', 'medidores.empresa_id', '=', 'empresas.id')
->leftJoin('tipo_medidor', 'medidores.cod_tipo_medidor', '=', 'tipo_medidor.id')
->leftJoin('tipo_canal_med as tipo1', 'medidores.canal1', '=', 'tipo1.id')
->leftJoin('tipo_canal_med as tipo2', 'medidores.canal2', '=', 'tipo2.id')
->whereNull('medidores.deleted_at')
->get();

3. 处理关联表的软删除

如果关联表也使用了软删除,需要在连接时排除这些表中已删除的记录,用闭包的方式添加额外条件:

$datos = Medidore::select([ 
    'medidores.*', 
    'empresas.name as empresa', 
    'tipo_medidor.descripcion as tipomedidor', 
    'tipo1.descripcion as canal_1', 
    'tipo2.descripcion as canal_2'
])
->join('empresas', function($join) {
    $join->on('medidores.empresa_id', '=', 'empresas.id')
         ->whereNull('empresas.deleted_at');
})
->join('tipo_medidor', function($join) {
    $join->on('medidores.cod_tipo_medidor', '=', 'tipo_medidor.id')
         ->whereNull('tipo_medidor.deleted_at');
})
->join('tipo_canal_med as tipo1', function($join) {
    $join->on('medidores.canal1', '=', 'tipo1.id')
         ->whereNull('tipo1.deleted_at');
})
->join('tipo_canal_med as tipo2', function($join) {
    $join->on('medidores.canal2', '=', 'tipo2.id')
         ->whereNull('tipo2.deleted_at');
})
->whereNull('medidores.deleted_at')
->get();

4. 简化软删除过滤(可选)

如果你的Medidore模型已经引入了SoftDeletes trait,那么Medidore::get()默认就会排除软删除的记录,所以whereNull('medidores.deleted_at')可以省略,代码会更简洁。

内容的提问来源于stack exchange,提问作者pmiranda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:49:15