[英]How to get last inserted non incremental id using eloquent in Laravel?
I have two models Customer
and Address
. 我有两个模型
Customer
和Address
。 My Customer
has non incremental primary key and is of type string
which is customer_id
. 我的
Customer
具有非增量主键,类型为string
,其值为customer_id
。 The relationship between these two models is of one to many, that means for single customer
many addresses
for example: invoice address, delivery address, current address, etc. My Customer
model is as shown below: 这两个模型之间的关系是一对多的,例如对于单个
customer
很多addresses
:发票地址,收货地址,当前地址等。我的Customer
模型如下所示:
Customer.php Customer.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
protected $keyType = 'string';
protected $primaryKey = 'customer_id';
public $incrementing = false;
public function addresses()
{
return $this->hasMany('App\Address','customer_id');
}
}
And my Address model is as shown below: 我的地址模型如下所示:
Address.php Address.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Address extends Model
{
//
public $timestamps = false;
// protected $table = "addresses";
public function customer()
{
return $this->belongsTo('App\Customer');
}
}
And following shows the migration for my customers table 以下显示了我的客户表的迁移
migration for customers table 客户迁移表
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCustomersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('customers', function (Blueprint $table) {
$table->string('customer_id');
$table->string('name');
$table->string('type');
$table->date('dob');
$table->type('country_code');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('customers');
}
}
The other thing to note is that my customer_id
is incremental in sense that I have created separate table namely customer_sequence
which is auto incremental and before inserting record I append it with two character code using trigger and then place it into my customers
table. 要注意的另一件事是我的
customer_id
是增量的,因为我已经创建了一个单独的表,即customer_sequence
,该表是自动增量的,在插入记录之前,我使用触发器将其附加两个字符代码,然后将其放置到我的customers
表中。 My customer_sequence migration is as shown below 我的customer_sequence迁移如下所示
customer_sequence Migration 客户序列迁移
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSequenceCustomers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sequence_customers', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sequence_customers');
}
}
And the trigger that I have used for inserting incrementing string id is as follows: 我用于插入增量字符串id的触发器如下:
Migration for customer_id trigger 迁移customer_id触发器
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTriggerCustomers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::unprepared("
CREATE TRIGGER tg_customer_insert
BEFORE INSERT ON customers
FOR EACH ROW
BEGIN
INSERT INTO sequence_customers(id) VALUES (NULL);
IF NEW.type ='Private' THEN
SET NEW.customer_id = CONCAT(NEW.country_code, LPAD(LAST_INSERT_ID(), 5, '0'));
ELSEIF NEW.type='Business' THEN
SET NEW.customer_id = CONCAT(NEW.country_code, LPAD(LAST_INSERT_ID(), 5, '0'));
ELSEIF NEW.type='Reseller' THEN
SET NEW.customer_id = LPAD(LAST_INSERT_ID(), 5, '0');
ELSEIF NEW.type='Distributor' THEN
SET NEW.customer_id = LPAD(LAST_INSERT_ID(), 5, '0');
ELSEIF NEW.type='Other' THEN
SET NEW.customer_id = LPAD(LAST_INSERT_ID(), 5, '0');
END IF;
IF NEW.credit_amount > NEW.credit_limit THEN
SET NEW.credit_limit_exceeded=TRUE;
ELSE
SET NEW.credit_limit_exceeded=FALSE;
END IF;
END
");
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::unprepared('DROP TRIGGER IF EXISTS tg_customer_insert');
}
}
Now when I save the data of customer and try to get id
from customer model it returns me null
. 现在,当我保存客户数据并尝试从客户模型获取
id
,它将返回null
。 My controller is as shown below: 我的控制器如下图所示:
CustomerController.php CustomerController.php
public function store(Request $request)
{
$customer = new Customer;
$invoiceAddress = new Address;
$deliveryAddress = new Address;
$customer->name = $request->name;
$customer->type = $request->type;
$customer->dob = $request->dob;
$customer->country_code=$request->country_code;
$customer->save();
$deliveryAddress->street_name_no = $request->street_name_no;
$deliveryAddress->city = $request->city;
$deliveryAddress->country = $request->country;
//This throws error customer_id cannot be null integrity constraint
$deliveryAddress->customer_id = $customer->customer_id;
$deliveryAddress->save();
}
This is because you are assigning request values to your customer variable. 这是因为您正在将请求值分配给客户变量。
$customer=new Customer;
$customer=$request->name;
$customer=$request->type;
$customer=$request->dob;
$customer->save();
When you are calling save()
, you are actually calling save()
on a string. 当您调用
save()
,实际上是在字符串上调用save()
。 Fix it by specifying the fillable properties on your Customer
model. 通过在
Customer
模型上指定可填充属性来对其进行修复。 This is just an example. 这只是一个例子。
$customer = new Customer();
$customer->name = $request->name;
$customer->type = $request->type;
$customer->dob = $request->dob;
$customer->save();
After that, $customer->customer_id
should not be null. 之后,
$customer->customer_id
不应为null。
Edit: Failed to notice the following line: 编辑:无法注意到以下行:
public $incrementing = false;
which means at the time of creating your Customer
you would also have to supply the customer_id
, since it is no longer auto-incrementing. 这意味着在创建
Customer
您还必须提供customer_id
,因为它不再自动递增。
I also took a deeper look at the API. 我还对API进行了更深入的研究。 It seems Laravel won't be aware of the attribute set by the trigger at that stage.
在该阶段,Laravel似乎不会意识到触发器设置的属性。 You can try to
refresh()
the model which will pull in fresh attributes from the DB and assuming your triggers are working fine, you should be getting back a customer_id
. 您可以尝试
refresh()
模型,该模型将从数据库中获取新的属性,并假设触发器工作正常,那么您应该找回customer_id
。
So essentially, just add this line before adding the Delivery Address. 因此,基本上,只需在添加传递地址之前添加此行。
$customer->refresh();
I also noticed you don't have any logic to redirect the user back on successful save. 我还注意到,您没有任何逻辑将用户重定向到成功保存后的状态。 I suspect this is why it is throwing the 404 since the same route isn't defined for a
GET
request. 我怀疑这就是为什么它抛出404的原因,因为未为
GET
请求定义相同的路由。
public function store(Request $request)
{
$customer = new Customer;
$invoiceAddress = new Address;
$deliveryAddress = new Address;
$customer->name = $request->name;
$customer->type = $request->type;
$customer->dob = $request->dob;
$customer->country_code = $request->country_code;
$customer->save();
$customer->refresh();
$deliveryAddress->street_name_no = $request->street_name_no;
$deliveryAddress->city = $request->city;
$deliveryAddress->country = $request->country;
$deliveryAddress->customer_id = $customer->customer_id;
$deliveryAddress->save();
return back()->with('success', 'Success message here');
}
Edited again: 再次编辑:
It seems from the doc, the refresh()
method is as follows: 从文档看来,
refresh()
方法如下:
/**
* Reload the current model instance with fresh attributes from the database.
*
* @return $this
*/
public function refresh()
{
if (! $this->exists) {
return $this;
}
$this->setRawAttributes(
static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes
);
$this->load(collect($this->relations)->except('pivot')->keys()->toArray());
$this->syncOriginal();
return $this;
}
As you can see from the following line: 从下面的行中可以看到:
static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes
It will try to find or fail (404) while refreshing the model. 刷新模型时,它将尝试查找或失败(404)。 I suspect in this case, that it is not able to get the appropriate key and that is why it is failing.
我怀疑在这种情况下,它无法获取适当的密钥,这就是为什么它失败了。 I think in this particular case, you will have to get the
customer_id
from the sequence_customers
table. 我认为在这种特殊情况下,您将不得不从
sequence_customers
表中获取customer_id
。
Maybe you could get away by doing something like the following: 也许您可以通过执行以下操作来摆脱困境:
// Assuming SequenceCustomer is the model name
$latest = \App\SequenceCustomer::latest()->first();
// and then you would be able to access the latest customer_id by doing the following
$customer_id = $latest->customer_id;
This is obviously not a scalable solution, but I am not very sure how else to solve this particular issue :) 这显然不是一个可扩展的解决方案,但是我不太确定该如何解决这个问题:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.