如何将组合键放入 Laravel 5 的模型中?
How I can put composite keys in models in Laravel 5?
我的数据库中有一个带有两个主键(id 和 language_id)的 table,我需要将其放入我的模型中。模型中的默认主键(Laravel 5 中的Model.php)是 id,我希望主键是 id 和 id_language。我尝试将它与数组或带有“,”的字符串放在一起,但它不起作用。它告诉我无法将数组转换为字符串。
你不能。 Eloquent 不支持复合主键。
它似乎变了,因为这个至少适用于 Laravel 5.1:
$table->primary(['key1', 'key2']);
我只是 运行 迁移和我在数据库中看到的内容适合我在上面的代码中输入的内容(当然上面的名称字段仅用于演示目的)。
Update:这对于迁移来说是正确的,但是一旦你想通过 eloquent 插入它就不适用于复合键并且永远不会(最后一条):
尝试查看此文档以插入与 CK 的多对多关系
https://laravel.com/docs/5.2/eloquent-relationships#inserting-many-to-many-relationships
编辑:一些额外信息
正如您在文档中看到的,attach 和 detach 函数创建了 CK 中间体 table 中所需的链接。所以你不必自己创建它们;)
你的情况是 model->languages()->attach(language_id)
我写了这个简单的 PHP trait 来适应 Eloquent 来处理复合键:
<?php
namespace App\Model\Traits; // *** Adjust this to match your model namespace! ***
use Illuminate\Database\Eloquent\Builder;
trait HasCompositePrimaryKey
{
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Set the keys for a save update query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function setKeysForSaveQuery(Builder $query)
{
foreach ($this->getKeyName() as $key) {
// UPDATE: Added isset() per devflow's comment.
if (isset($this->$key))
$query->where($key, '=', $this->$key);
else
throw new Exception(__METHOD__ . 'Missing part of the primary key: ' . $key);
}
return $query;
}
// UPDATE: From jessedp. See his edit, below.
/**
* Execute a query for a single record by ID.
*
* @param array $ids Array of keys, like [column => value].
* @param array $columns
* @return mixed|static
*/
public static function find($ids, $columns = ['*'])
{
$me = new self;
$query = $me->newQuery();
foreach ($me->getKeyName() as $key) {
$query->where($key, '=', $ids[$key]);
}
return $query->first($columns);
}
}
将其放在主模型目录下的 Traits
目录中,然后您可以在任何复合键模型的顶部添加一个简单的单行代码:
class MyModel extends Eloquent {
use Traits\HasCompositePrimaryKey; // *** THIS!!! ***
/**
* The primary key of the table.
*
* @var string
*/
protected $primaryKey = array('key1', 'key2');
...
由 jessedp 添加:
这对我来说非常有效,直到我想使用 Model::find ...所以下面是一些代码(可能会更好)可以添加到上面的 hasCompositePrimaryKey 特性中:
protected static function find($id, $columns = ['*'])
{
$me = new self;
$query = $me->newQuery();
$i=0;
foreach ($me->getKeyName() as $key) {
$query->where($key, '=', $id[$i]);
$i++;
}
return $query->first($columns);
}
2016-11-17更新
我现在将其作为名为 LaravelTreats.
的开源包的一部分进行维护
2020-06-10更新
LaravelTreats 已死,但无论如何请享受代码:)
多年来,一些深入的用例引起了我的注意,其中出现了故障。这应该适用于绝大多数用例,但要知道,如果你想变得花哨,你可能不得不重新考虑你的方法。
https://laravel.com/docs/5.3/migrations#columns
是的,你可以。
我分享我的迁移代码:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RegistroEmpresa extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('registro_empresa', function(Blueprint $table)
{
$table->string('licencia',24);
$table->string('rut',12);
$table->string('nombre_empresa');
$table->string('direccion');
$table->string('comuna_Estado');
$table->string('ciudad');
$table->string('pais');
$table->string('fono');
$table->string('email');
$table->string('paginaweb');
$table->string('descripcion_tienda');
$table->string('monedauso');
$table->timestamps();
$table->primary(['licencia', 'rut']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('registro_empresa');
}
}
在迁移中,您可以简单地为 table 定义复合主键,如@erick-suarez 和@sba 所说,在您的 Schema::create
或 Schema::table
块写入$table->primary(['key1', 'key2']);
在代表 table 的 Eloquent 模型 中,您不能直接将复合键与 Eloquent 方法一起使用,例如find($key)
或 save($data)
但您仍然可以使用
检索模型实例以供查看
$modelObject = ModelName->where(['key1' => $key1, 'key2' => $key2])->first();
如果您想更新 table 中的记录,您可以使用 QueryBuilder
方法,如下所示:
ModelName->where(['key1' => $key1, 'key2' => $key2])->update($data);
其中 $data
是您要用来更新模型的数据关联数组 ['attribute1' => 'value1', ..]
。
注意:您仍然可以安全地使用 Eloquent 关系来使用此类模型进行检索,因为它们通常用作枢轴 table 破坏许多-对多关系结构。
你可以尝试使用以下模块
https://github.com/maksimru/composite-primary-keys
只需将 HasCompositePrimaryKey 特征添加到您的模型并将数组值指定为主键
一个简单的解决方案,很适合我 (Laravel 5.7):
在模型中定义主键之一:
class MyTable extends Model
{
protected $primaryKey = 'user_id';
protected $table = 'my_table';
protected $fillable = ['user_id', 'post_id', 'flag'];
所以在Controller中传递两个主键,这里我用的是[=12=的两个参数中的第一个] 方法,接收两个数组:
控制器:
public function post_foo(Request $request)
{
//PK1 is user_id, PK2 is post_id
//flag - is the field that has its value changed
$task = MyTable::updateOrCreate(
['user_id' => $request->header('UID'),'post_id' => $request->input('post_id')],
['user_id' => $request->header('UID'),'post_id' => $request->input('post_id'),'flag' => $request->input('flag')]
);
return $task;
}
解释解决方案:
你没有id
列作为主键的问题在模型中只用一个主键就解决了,在数据库中正确的行是在控制器中用两个主键找到的。
我的数据库中有一个带有两个主键(id 和 language_id)的 table,我需要将其放入我的模型中。模型中的默认主键(Laravel 5 中的Model.php)是 id,我希望主键是 id 和 id_language。我尝试将它与数组或带有“,”的字符串放在一起,但它不起作用。它告诉我无法将数组转换为字符串。
你不能。 Eloquent 不支持复合主键。
它似乎变了,因为这个至少适用于 Laravel 5.1:
$table->primary(['key1', 'key2']);
我只是 运行 迁移和我在数据库中看到的内容适合我在上面的代码中输入的内容(当然上面的名称字段仅用于演示目的)。
Update:这对于迁移来说是正确的,但是一旦你想通过 eloquent 插入它就不适用于复合键并且永远不会(最后一条):
尝试查看此文档以插入与 CK 的多对多关系
https://laravel.com/docs/5.2/eloquent-relationships#inserting-many-to-many-relationships
编辑:一些额外信息
正如您在文档中看到的,attach 和 detach 函数创建了 CK 中间体 table 中所需的链接。所以你不必自己创建它们;)
你的情况是 model->languages()->attach(language_id)
我写了这个简单的 PHP trait 来适应 Eloquent 来处理复合键:
<?php
namespace App\Model\Traits; // *** Adjust this to match your model namespace! ***
use Illuminate\Database\Eloquent\Builder;
trait HasCompositePrimaryKey
{
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Set the keys for a save update query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function setKeysForSaveQuery(Builder $query)
{
foreach ($this->getKeyName() as $key) {
// UPDATE: Added isset() per devflow's comment.
if (isset($this->$key))
$query->where($key, '=', $this->$key);
else
throw new Exception(__METHOD__ . 'Missing part of the primary key: ' . $key);
}
return $query;
}
// UPDATE: From jessedp. See his edit, below.
/**
* Execute a query for a single record by ID.
*
* @param array $ids Array of keys, like [column => value].
* @param array $columns
* @return mixed|static
*/
public static function find($ids, $columns = ['*'])
{
$me = new self;
$query = $me->newQuery();
foreach ($me->getKeyName() as $key) {
$query->where($key, '=', $ids[$key]);
}
return $query->first($columns);
}
}
将其放在主模型目录下的 Traits
目录中,然后您可以在任何复合键模型的顶部添加一个简单的单行代码:
class MyModel extends Eloquent {
use Traits\HasCompositePrimaryKey; // *** THIS!!! ***
/**
* The primary key of the table.
*
* @var string
*/
protected $primaryKey = array('key1', 'key2');
...
由 jessedp 添加:
这对我来说非常有效,直到我想使用 Model::find ...所以下面是一些代码(可能会更好)可以添加到上面的 hasCompositePrimaryKey 特性中:
protected static function find($id, $columns = ['*'])
{
$me = new self;
$query = $me->newQuery();
$i=0;
foreach ($me->getKeyName() as $key) {
$query->where($key, '=', $id[$i]);
$i++;
}
return $query->first($columns);
}
2016-11-17更新
我现在将其作为名为 LaravelTreats.
的开源包的一部分进行维护2020-06-10更新
LaravelTreats 已死,但无论如何请享受代码:)
多年来,一些深入的用例引起了我的注意,其中出现了故障。这应该适用于绝大多数用例,但要知道,如果你想变得花哨,你可能不得不重新考虑你的方法。
https://laravel.com/docs/5.3/migrations#columns
是的,你可以。
我分享我的迁移代码:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RegistroEmpresa extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('registro_empresa', function(Blueprint $table)
{
$table->string('licencia',24);
$table->string('rut',12);
$table->string('nombre_empresa');
$table->string('direccion');
$table->string('comuna_Estado');
$table->string('ciudad');
$table->string('pais');
$table->string('fono');
$table->string('email');
$table->string('paginaweb');
$table->string('descripcion_tienda');
$table->string('monedauso');
$table->timestamps();
$table->primary(['licencia', 'rut']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('registro_empresa');
}
}
在迁移中,您可以简单地为 table 定义复合主键,如@erick-suarez 和@sba 所说,在您的 Schema::create
或 Schema::table
块写入$table->primary(['key1', 'key2']);
在代表 table 的 Eloquent 模型 中,您不能直接将复合键与 Eloquent 方法一起使用,例如find($key)
或 save($data)
但您仍然可以使用
$modelObject = ModelName->where(['key1' => $key1, 'key2' => $key2])->first();
如果您想更新 table 中的记录,您可以使用 QueryBuilder
方法,如下所示:
ModelName->where(['key1' => $key1, 'key2' => $key2])->update($data);
其中 $data
是您要用来更新模型的数据关联数组 ['attribute1' => 'value1', ..]
。
注意:您仍然可以安全地使用 Eloquent 关系来使用此类模型进行检索,因为它们通常用作枢轴 table 破坏许多-对多关系结构。
你可以尝试使用以下模块
https://github.com/maksimru/composite-primary-keys
只需将 HasCompositePrimaryKey 特征添加到您的模型并将数组值指定为主键
一个简单的解决方案,很适合我 (Laravel 5.7):
在模型中定义主键之一:
class MyTable extends Model
{
protected $primaryKey = 'user_id';
protected $table = 'my_table';
protected $fillable = ['user_id', 'post_id', 'flag'];
所以在Controller中传递两个主键,这里我用的是[=12=的两个参数中的第一个] 方法,接收两个数组:
控制器:
public function post_foo(Request $request)
{
//PK1 is user_id, PK2 is post_id
//flag - is the field that has its value changed
$task = MyTable::updateOrCreate(
['user_id' => $request->header('UID'),'post_id' => $request->input('post_id')],
['user_id' => $request->header('UID'),'post_id' => $request->input('post_id'),'flag' => $request->input('flag')]
);
return $task;
}
解释解决方案:
你没有id
列作为主键的问题在模型中只用一个主键就解决了,在数据库中正确的行是在控制器中用两个主键找到的。