我需要创建一个包含复合主键的表。我一直在寻找解决问题的多个选项,以创建一个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
由带字段的数组组成的表,而不是而不是只有一个主键。
此外,尽管出现了这个错误,但是第一个种子'确实被添加到数据库中,但没有添加。
答案 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);
}
}