Laravel Eloquent CANNOT Save Models with Composite

2019-02-25 12:24发布

问题:

When defining composite primary keys then calling save on an instanced model, an exception is thrown.

ErrorException (E_UNKNOWN) 
PDO::lastInsertId() expects parameter 1 to be string, array given

The error occurred at line 32

$id = $query->getConnection()->getPdo()->lastInsertId($sequence);

And here's the declaration of Model

class ActivityAttendance extends Eloquent {
    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'activity_attendance';

    /**
     * The primary key of the table.
     * 
     * @var string
     */
    protected $primaryKey = array('activity_id', 'username');

    /**
     * The attributes of the model.
     * 
     * @var array
     */
    protected $guarded = array('activity_id', 'username', 'guests');

    /**
     * Disabled the `update_at` field in this table.
     * 
     * @var boolean
     */
    public $timestamps = false;
}

Here's the code to create new record in Controller class.

$attendance                 = new ActivityAttendance;
$attendance->activity_id    = $activityId;
$attendance->username       = $username;
$attendance->save();

回答1:

I'm assuming this is a pivot table, in which case you shouldn't be working with the pivot table directly. Work with either the Activity or Attendance models using the methods on belongsToMany() to update the pivot table, sync(), attach(), detach(), etc...

If for some reason that is not possible because your pivot table also contains keys going elsewhere, you should remove the current primary key, add an id auto-increment primary key column and add a unique index to username, and activity_id.

You may be able to save it like this as well... might be worth a shot.

$attendance = ActivityAttendance::create(
    'activity_id' => $activityId,
    'username' => $username
);


回答2:

You can only use ::create() on attributes you listed in your model's fillable attribute.

class ActivityAttendance extends Model {
...
    protected $fillable = ['activity_id', 'username'];
...
}


回答3:

In simple scenario one may also face same error. So when creating composite primary key in models you also need to override $incrementing property in your model definition. If not declared you'll also get exact same error i.e [ErrorException' with message 'PDO::lastInsertId() expects parameter 1 to be string].

Reason maybe Eloquent try to get value of last auto-number. However its true that Laravel don't have full support of composite keys and we are mostly bound to use Query Builder approach.

class ActivityAttendance extends Eloquent {
   ...
   protected $incrementing = false;
   ...
}