Laravel Query Builder参数映射错误原因及修复方法咨询
错误成因
- 参数绑定顺序完全错位:Laravel查询构建器是按参数添加的先后顺序来匹配SQL占位符的。你用
DB::raw硬写了billable_type = 'App\Models\Citation',直接打乱了withSum的自动绑定逻辑——withSum原本会给多态关联的billable_type生成占位符并绑定正确值,但硬编码的字符串抢占了参数位置,导致后续的日期参数被错误塞到了withSum的占位符里,同时withSum的类型值又跑到了日期条件的位置,造成两处参数完全错位。 - 破坏多态关联的自动处理规则:
settlements属于多态关联,withSum会自动从Citation模型的关联定义里读取billable_type的值,根本不需要手动硬编码。你在DB::raw里写死类型字符串,直接破坏了框架的参数绑定流程,引发连锁错误。
修复方案
替换硬编码子查询,用查询构建器规范实现
把原来的DB::raw子查询改成Laravel原生查询构建器语法,让框架自动处理参数绑定,避免顺序混乱:
// 先构建支付统计的子查询 $paymentsSubquery = Settlement::query() ->select('billable_id') ->selectRaw('sum(amount_dollars) as amount_paid') ->where('billable_type', Citation::class) // 用类常量替代硬编码,框架自动绑定参数 ->whereNull('deleted_at') ->groupBy('billable_id'); // 主查询重构 Citation::with([ 'person:id,name_first,name_last', 'employer:id,name', 'incident', ]) ->withSum('settlements', 'amount_dollars') ->leftJoinSub($paymentsSubquery, 'payments', function (JoinClause $join) { $join->on('payments.billable_id', '=', 'citations.id') ->whereColumn( DB::raw('`citations`.`amount_dollars` - `citations`.`amount_discount_dollars`'), '>', 'amount_paid' ); }) ->whereDate('created_at', '>=', '2017-10-16') ->whereDate('created_at', '<=', now()) // 用now()动态获取当前日期,避免写死 ->get();
关键修复点说明
- 用
leftJoinSub替代leftJoin+DB::raw,让子查询的参数绑定完全由框架接管,避免手动硬编码干扰全局参数顺序。 - 用
Citation::class替代硬编码的类名字符串,既保证类型值准确,又让框架自动处理参数绑定,避免占位符错位。 - 用
whereDate替代直接where,明确针对日期部分查询,同时用now()动态获取当前日期,提升代码灵活性。
内容的提问来源于stack exchange,提问作者Jay Bienvenu
相关产品推荐
相关产品推荐

