我有两个模型Customer
和Address
。我的Customer
具有非增量主键,类型为string
,类型为customer_id
。这两个模型之间的关系是一对多的,例如,对于单个customer
,许多addresses
:发票地址,收货地址,当前地址等。我的Customer
模型是如下所示:
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');
}
}
我的地址模型如下所示:
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');
}
}
以下显示了我的客户表的迁移
客户迁移表
<?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');
}
}
要注意的另一件事是我的customer_id
是增量的,因为我已经创建了一个单独的表customer_sequence
,该表是自动增量的,在插入记录之前,我使用触发器和两个字符代码附加了它然后将其放入我的customers
表中。
我的customer_sequence迁移如下所示
customer_sequence迁移
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');
}
}
我用于插入递增字符串id的触发器如下:
迁移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');
}
}
现在,当我保存客户数据并尝试从客户模型中获取id
时,它将返回我null
。我的控制器如下所示:
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();
}
答案 0 :(得分:1)
这是因为您正在将请求值分配给客户变量。
$customer=new Customer;
$customer=$request->name;
$customer=$request->type;
$customer=$request->dob;
$customer->save();
在调用save()
时,实际上是在字符串上调用save()
。
通过在Customer
模型上指定可填充属性来解决此问题。这只是一个例子。
$customer = new Customer();
$customer->name = $request->name;
$customer->type = $request->type;
$customer->dob = $request->dob;
$customer->save();
此后,$customer->customer_id
不应为null。
编辑:无法注意到以下行:
public $incrementing = false;
,这意味着在创建Customer
时,您还必须提供customer_id
,因为它不再自动递增。
我还对API进行了更深入的研究。在该阶段,Laravel似乎不会意识到触发器设置的属性。您可以尝试refresh()
该模型将从数据库中获取新的属性,并假设触发器工作正常,那么您应该找回customer_id
。
从本质上讲,只需在添加传递地址之前添加此行即可。
$customer->refresh();
我还注意到您没有任何逻辑将用户重定向到成功保存后的状态。
我怀疑这就是为什么抛出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');
}
再次编辑:
从文档看来,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;
}
从下面的行中可以看到:
static::newQueryWithoutScopes()->findOrFail($this->getKey())->attributes
在刷新模型时,它将尝试查找或失败(404)。我怀疑在这种情况下,它无法获取适当的密钥,这就是为什么它失败了。我认为在这种情况下,您将不得不从customer_id
表中获取sequence_customers
。
也许您可以通过执行以下操作来摆脱困境:
// 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;
这显然不是可扩展的解决方案,但是我不太确定该如何解决这个问题的其他方法:)