Laravel 8.61.0在MSSQL环境下Eager Loading关联查询失效如何解决
问题根因
该问题是MSSQL和MySQL的类型隐式转换规则、字段返回格式差异导致的:懒加载执行的是单条关联查询,MSSQL在部分场景下兼容隐式类型转换,可以正常返回结果;但预加载使用whereIn查询关联数据时类型校验更严格,匹配不到对应数据导致关联属性为null,最终报错。
修复方案
按优先级依次排查即可:
第一步:校验关联键字段类型一致性
检查Order表customer_key和Client表customer_fk的字段类型是否完全匹配:不要出现一边是int一边是varchar的情况,MySQL支持不同类型的隐式转换,但MSSQL不支持,whereIn查询会直接匹配不到结果。
如果因业务逻辑无法统一字段类型,在两个模型的对应字段添加类型转换,统一格式:// Order 模型 protected $casts = [ 'customer_key' => 'string', // 如果是数值类型就改成'int' ]; // Client 模型 protected $casts = [ 'customer_fk' => 'string', // 和上面的转换类型保持一致 ];第二步:处理MSSQL字段格式问题
- MSSQL默认返回的字段名是大写形式,和关联定义的小写键名不匹配,可在数据库配置
config/database.php的sqlsrv节点下添加PDO属性,自动把返回字段名转成小写:
'sqlsrv' => [ // 原有配置保持不变 'options' => [ PDO::ATTR_CASE => PDO::CASE_LOWER, PDO::ATTR_STRINGIFY_FETCHES => true, ], ]- 如果外键是
char固定长度类型,MSSQL存储时会自动补全尾随空格,导致匹配失败,可在关联定义时添加trim处理:
public function client(): HasOne { return $this->hasOne(Client::class, 'customer_fk', \DB::raw('TRIM(customer_key)')); }- MSSQL默认返回的字段名是大写形式,和关联定义的小写键名不匹配,可在数据库配置
第三步:调试定位
开启SQL日志打印预加载的执行语句,复制到MSSQL管理工具手动执行,可快速定位具体匹配失败的原因:\DB::enableQueryLog(); $order = Order::with(['client'])->find(1); dd(\DB::getQueryLog());
内容的提问来源于stack exchange,提问作者Chan
相关产品推荐
相关产品推荐

