Laravel种子表与复合主键

时间:2014-06-10 22:44:41

标签: php pdo laravel laravel-4

我需要创建一个包含复合主键的表。我一直在寻找解决问题的多个选项,以创建一个AUTO_INCREMENT字段以及其他一些字段,并使它们成为复合主键,但最终我成功完成了这样做;

class CreateSpecificationTable extends Migration {

    public function up()
    {
        Schema::create('specification', function(Blueprint $table){
            $table->increments('specificationID');
            $table->integer('categoryID', false, true);
            $table->string('name', 100);

            $table->dateTime('created_at');
            $table->dateTime('updated_at')->nullable()->default(null);
            $table->dateTime('deleted_at')->nullable()->default(null);

            $table->foreign('categoryID')->references('categoryID')->on('categories');
        });

        DB::unprepared('ALTER TABLE specification DROP PRIMARY KEY, ADD PRIMARY KEY(specificationID, categoryID, name)');
    }

此表的模型非常简单:

class Specification extends Eloquent {

    protected $table = 'specification';
    protected $primaryKey = array('specificationID', 'categoryID', 'name');
}

然后播种机看起来像这样:

class SpecificationSeeder extends Seeder {

    public function run()
    {
        Specification::create(array(
        'categoryID'=>1,
        'name'=>'size',
        ));

        Specification::create(array(
        'categoryID'=>2,
        'name'=>'resolution',
        ));

        Specification::create(array(
        'categoryID'=>1,
        'naam'=>'connection',
        ));
    }
}

但是,当我从CMD运行php artisan db:seed命令时,出现以下错误:

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

奇怪的是,我已经用这种方式在这个应用程序中构建了很多其他表,但这是第一个模型中的protected $primaryKey由带字段的数组组成的表,而不是而不是只有一个主键。

此外,尽管出现了这个错误,但是第一个种子'确实被添加到数据库中,但没有添加。

3 个答案:

答案 0 :(得分:1)

Eloquent不支持复合键。您可以使用以下两种方法之一来完成此工作:

1)使用Schema Builder作为Seeder,并保持您的迁移不变。

class SpecificationSeeder extends Seeder {

    public function run()
    {
        $data = array(
            array(
                'categoryID'=>1,
                'name'=>'size',
            ),
            array(
                'categoryID'=>1,
                'name'=>'size',
            ),
            array(
                'categoryID'=>1,
                'naam'=>'connection',
            )
        );

        DB::table('specification')->insert($data);
    }
}

2)更改迁移,添加主键并定义唯一键。将播种机保持原样

class CreateSpecificationTable extends Migration {

    public function up()
    {
        Schema::create('specification', function(Blueprint $table){
            $table->increments('id');
            $table->integer('specificationID');
            $table->integer('categoryID', false, true);
            $table->string('name', 100);

            $table->dateTime('created_at');
            $table->dateTime('updated_at')->nullable()->default(null);
            $table->dateTime('deleted_at')->nullable()->default(null);

            $table->unique( array('specificationID', 'categoryID', 'name') );

            $table->foreign('categoryID')->references('categoryID')->on('categories');
        });
    }
}

答案 1 :(得分:1)

Laravel 4确实支持复合键。此外,最好还是正确设置主键,而不是使用foreign()语法。

正如文档中所述:

$table->primary('specificationID');创建主键。但是,由于您使用的是increments('id');,因此您已将主键作为ID。因此,除非您实际存储预定义且不变的规范的ID,否则您的列规范ID是多余的。

$table->primary(array('specificationID', 'categoryID', 'name'));创建一个复合键

一般情况下,我会尝试尽可能缩短您的综合索引,如果绝对必要,只包括列。你真的需要为你的密钥添加名字吗?我意识到对于较小的应用程序,这可能不那么重要,只是试图说出最佳实践。

答案 2 :(得分:1)

我成功地让Laravel 5.1使用复合键。首先将您的架构定义为:

class CreateSpecificationTable extends Migration
{

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('specification', function(Blueprint $table){
            $table->primary(array('specificationID', 'categoryID', 'name'));
            $table->integer('categoryID', false, true);
            $table->string('name', 100);
            $table->dateTime('created_at');
            $table->dateTime('updated_at')->nullable()->default(null);
            $table->dateTime('deleted_at')->nullable()->default(null);
            $table->foreign('categoryID')->references('categoryID')->on('categories');
        });
    }

你的模特:

class Specification extends Eloquent {

    protected $table = 'specification';
    protected $primaryKey = array('specificationID', 'categoryID', 'name');
    public $incrementing = false; //important to avoid exception PDO::lastInsertId() expects parameter 1 to be string, array given
}

如果您需要更新或删除模型,则需要override setKeysForSaveQuery方法:

protected function setKeysForSaveQuery(\Illuminate\Database\Eloquent\Builder $query)
{
    if(is_array($this->primaryKey)) {
        foreach($this->primaryKey as $pk) {
            $query->where($pk, '=', $this->original[$pk]);
        }
        return $query;
    } else {
        return parent::setKeysForSaveQuery($query);
    }
}