laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.52k stars 11.02k forks source link

bug: eloquent sync(), syncWithPivotValues(), syncWithoutDetaching() return auto convert to int or bigint #48926

Closed Plong-Wasin closed 1 year ago

Plong-Wasin commented 1 year ago

Laravel Version

10.30.1

PHP Version

8.2.10

Database Driver & Version

Microsoft SQL Server 2022 (RTM-CU8) (KB5029666) - 16.0.4075.1 (X64) Aug 23 2023 14:04:50 Copyright (C) 2022 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 20.04.6 LTS)

Description

first bug

this bug return wrong value it convert to bigint but keytype is string

A::first()->b()->sync(['11111111111111111111' => ['qty' => 1]],false);
// output
[
    "attached" => [
      9223372036854775807,
    ],
    "detached" => [],
    "updated" => [],
  ]
// in database it store 11111111111111111111 is corrent
A::first()->b()->sync(['aaaaaab'],false);
//output
[
    "attached" => [
      0,
    ],
    "detached" => [],
    "updated" => [],
  ]

second bug

if in db store string and run sync, syncWithPivotValues, syncWithoutDetaching and set detaching = false it return error Illuminate\Database\QueryException SQLSTATE[22018]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Conversion failed when converting the nvarchar value 'a' to data type int. (Connection: sqlsrv, SQL: update [ab] set [qty] = 2 where [ab].[a_id] = 1 and [b_id] in (1)).

A::first()->b()->sync(['a'=>['qty'=>2]],false);
A::first()->b()->sync(['1'=>['qty'=>2]],false);
A::first()->b()->sync(['1'=>['qty'=>2]],false);

Sorry i not good in english.

Steps To Reproduce

  1. create project
  2. set db to sqlserver
  3. create migration and model
<?php
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('a_s', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }
};
<?php
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('b_s', function (Blueprint $table) {
            $table->string();
            $table->timestamps();
        });
    }
};
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('ab', function (Blueprint $table) {
            $table->unsignedBigInteger('a_id');
            $table->string('b_id');
            $table->integer('qty')->nullable()->default(1);
            $table->timestamps();
        });
    }
};
class A extends Model
{
    use HasFactory;
    public $timestamps = false;
    public function b()
    {
        return $this->belongsToMany(B::class, 'ab', 'a_id', 'b_id');
    }
}
class B extends Model
{
    use HasFactory;
}
  1. run first bug
(new A())->save();
A::first()->b()->sync(['11111111111111111111' => ['qty' => 1]],false);
// output
[
    "attached" => [
      9223372036854775807,
    ],
    "detached" => [],
    "updated" => [],
  ]
// in database it store 11111111111111111111 is corrent
  1. run second bug
(new A())->save();
A::first()->b()->sync(['a'=>['qty'=>2]],false);
A::first()->b()->sync(['1'=>['qty'=>2]],false);
A::first()->b()->sync(['1'=>['qty'=>2]],false);
crynobone commented 1 year ago

Shouldn't B model have the following:

class B extends Model
{
    use HasFactory;
+   protected $keyType = 'string';
}