【问题标题】:Laravel seed table with composite primary key具有复合主键的 Laravel 种子表
【发布时间】:2014-07-31 20:50:53
【问题描述】:

我需要用复合主键创建一个表。我一直在寻找多种选项来解决问题,以创建一个 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 由一个包含字段的数组组成,而不是一个单独的首要的关键。

此外,尽管出现此错误,但第一个“种子”确实会添加到数据库中,但之后就没有了。

【问题讨论】:

    标签: php pdo laravel laravel-4


    【解决方案1】:

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

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

    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');
            });
        }
    }
    

    【讨论】:

      【解决方案2】:

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

      如文档中所述:

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

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

      一般来说,我会尽量保持您的复合索引尽可能短,并且仅在绝对必要时才包含列。您真的需要在密钥中添加名称吗?我意识到对于较小的应用程序,这可能不那么相关,只是想为最佳实践大声疾呼。

      【讨论】:

        【解决方案3】:

        我成功让 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
        }
        

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

        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);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2018-02-16
          • 2014-06-07
          • 2011-07-03
          • 2013-04-30
          • 1970-01-01
          • 2012-05-18
          • 2010-12-05
          • 2013-12-19
          • 1970-01-01
          相关资源
          最近更新 更多