Как получить последний вставленный не инкрементный идентификатор, используя eloquent в Laravel? - PullRequest
0 голосов
/ 30 декабря 2018

У меня есть две модели 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');
    }
}

И триггер, который я использовал для вставки идентификатора инкрементной строки, выглядит следующим образом:

Миграция для триггера 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();
}

1 Ответ

0 голосов
/ 30 декабря 2018

Это потому, что вы присваиваете значения запроса вашей переменной клиента.

$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 не должен быть нулевым.

Редактировать: не удалось заметить следующую строку:

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;

Это явно не масштабируемое решение, но я не совсем уверен, как еще решить эту конкретную проблему :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...