Laravel Eloquent使用UUID作为ID时部分关联返回NULL问题
在Laravel ^9.19版本中,使用\Str::uuid()生成UUID作为AffiliatorVoucher模型的ID,但部分AffiliatorVoucherMember关联的voucher返回NULL,尽管对应ID的凭证确实存在,另一部分关联却能正常运行。
结果打印代码
dump(\App\Models\AffiliatorVoucher::find('27a4093d-2370-4c55-bc44-1f8ef8144067')->toArray()); dd(\App\Models\AffiliatorVoucherMember::with('voucher')->find(172)->toArray());
模型代码
App\Models\AffiliatorVoucher
class AffiliatorVoucher extends Model { use HasFactory, SoftDeletes; protected $guarded = [ 'id', ]; protected $casts = [ 'detail' => 'object', ]; public $incrementing = false; public function members() :HasMany { return $this->hasMany(AffiliatorVoucherMember::class); } // ... other methods }
App\Models\AffiliatorVoucherMember
class AffiliatorVoucherMember extends Model { use HasFactory; protected $guarded = ['id']; protected $casts = [ 'detail' => 'object', ]; public function voucher() :BelongsTo { return $this->belongsTo(AffiliatorVoucher::class, 'affiliator_voucher_id'); } }
迁移文件
Affiliator Vouchers迁移
public function up() { Schema::create('affiliator_vouchers', function (Blueprint $table) { $table->uuid('id')->primary(); $table->foreignId('affiliator_id')->constrained()->onUpdate('cascade')->onDelete('cascade'); $table->foreignId('organization_id')->nullable()->constrained()->onUpdate('cascade')->onDelete('cascade'); $table->string('prefix')->nullable(); $table->string('code')->unique(); $table->tinyInteger('status')->default(1); $table->bigInteger('discount_amount')->unsigned()->nullable(); $table->decimal('discount_percentage', 5, 2)->unsigned()->nullable(); $table->json('detail')->nullable(); $table->timestamps(); $table->softDeletes(); }); }
Affiliator Voucher Member迁移
public function up() { Schema::create('affiliator_voucher_members', function (Blueprint $table) { $table->id(); $table->foreignUuid('affiliator_voucher_id')->constrained()->onUpdate('cascade')->onDelete('cascade'); $table->string('unique_id')->unique()->nullable(); $table->string('name')->nullable(); $table->string('email')->nullable(); $table->json('detail'); $table->timestamps(); }); }
排查与解决方案
检查UUID大小写一致性
数据库中affiliator_voucher_members.affiliator_voucher_id与affiliator_vouchers.id的UUID大小写可能存在差异,MySQL在utf8_bin等编码下字符串比较区分大小写,会导致关联失败。直接查询数据库对比两个字段的UUID值是否完全一致。明确模型主键类型
在AffiliatorVoucher模型中添加protected $keyType = 'string';,Laravel默认主键类型为int,仅设置$incrementing = false未指定$keyType,可能导致查询时类型不匹配,引发部分关联失效。排查软删除影响
AffiliatorVoucher使用了SoftDeletes,默认关联查询不会包含已软删除的记录。若关联的凭证被软删除,可修改关联方法加入withTrashed():public function voucher() :BelongsTo { return $this->belongsTo(AffiliatorVoucher::class, 'affiliator_voucher_id')->withTrashed(); }或直接确认目标凭证未被软删除。
查看实际执行的SQL
开启查询日志,检查关联查询的SQL语句是否正确:DB::enableQueryLog(); $member = \App\Models\AffiliatorVoucherMember::with('voucher')->find(172); dd(DB::getQueryLog());将生成的SQL直接在数据库中执行,验证是否能返回预期结果,定位SQL层面的问题。
验证外键数据一致性
执行SQL查询SELECT * FROM affiliator_vouchers WHERE id = (SELECT affiliator_voucher_id FROM affiliator_voucher_members WHERE id = 172),确认关联的凭证记录确实存在,排除数据不一致的情况。
内容的提问来源于stack exchange,提问作者darektoa

