Как динамически построить этот запрос - Laravel / Lumen - PullRequest
1 голос
/ 06 февраля 2020

У меня есть следующий ввод от пользователя:

array (
  'id_coretable' => 1,
  'Internal_key' => 'UPDATED1',
  'extensiontable_itc' => 
  array (
    'description_itc' => 'UPDATED1',
  ),
  'extensiontable_sysops' => 
  array (
    'description_sysops' => 'UPDATED1',
  ),
)  

и его содержимое должно обновить следующую модель:

array (
  'id_coretable' => 1,
  'Internal_key' => 'TESTKEY_1',
  'extensiontable_itc' => 
  array (
    'description_itc' => 'EXTENSION_ITC_1',
  ),
  'extensiontable_sysops' => 
  array (
    'description_sysops' => 'EXTENSION_SYSOPS_1',
  ),
)  

Эта модель была создана с этим кодом:

$joinAsArray = coretable::with($permittedTables)->find(1);

Где $permittedTables - это массив имен таблиц, которые определяют таблицы, которые нужно объединить с coretable.

Теперь я потратил несколько часов на размышления о том, как правильно l oop над модель, и это просто невозможно без сериализации модели в простой массив или тому подобное. Это действительно не помогает, так как я хочу обновить модель здесь, и если я просто преобразую ее в массив, я потеряю это соединение с БД / моделью.

Так что я сейчас использую другой подход. Я зацикливаю пользовательский ввод, который ВСЕГДА будет иметь ту же структуру и индексы, что и модель. А затем я использую ключи из очень хорошо зацикливаемого userinputarray и копию старой модели в виде массива, чтобы определить атрибуты модели, которые должны быть обновлены соответствующими входными данными. Вот как выглядит мой код:

foreach($input as $key => $value){
  foreach($modelAsArray as $keyOld => $valueOld){ 

  //$keyOld is ALWAYS the same key as the "new" one. 
  //$keyOld was only chosen to both distinguish from the outer loops $key and to 
  //maintain its relationship to $valueOld, which is indeed the old value! ;)

    coretable::with($permittedTables)->where($key, $valueOld)->update([$key => $value]);
  }
}

Теперь этот код работает довольно аккуратно для внешнего массива. Я действительно могу обновить поле «Internal_key» таким образом. Однако, как только мы дойдем до точки, где объединенная таблица будет представлена ​​в виде «вложенного массива», вещи go на юг. Я получаю следующее сообщение об ошибке:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'extensiontable_itc' in 'where clause' (SQL: update `coretable` set `extensiontable_itc` = {"description_itc":"UPDATED1"}, `coretable`.`updated_at` = 2020-02-06 16:07:06 where `extensiontable_itc` = UPDATED1)

Я вижу, как это происходит. Он пытается найти столбец extensiontable_itc на coretable, которого, очевидно, там нет, так как это его собственное отношение, связанное только с coretable через FK.

Первое, что приходит мне в голову, чтобы разобраться с этой проблемой, это вызвать другую модель, динамически вставляя ее имя с помощью клавиши $. Тогда мне нужно будет l oop над ключами и значениями вложенных массивов, в основном делая то же самое, что я делал с внешним массивом.

Это, вероятно, потребует сравнительно ужасное количество ресурсов, но это программное обеспечение только для внутренних целей, и наш DB-сервер, вероятно, сможет справиться с этой нагрузкой. Я думаю, это тоже довольно хакерски ^^

Итак, кто-нибудь еще может дать мне другое, более элегантное, менее требовательное к ресурсам и менее хакерское решение, чем мое?

РЕДАКТИРОВАТЬ: В соответствии с запросом в комментариях, вот мои миграции:

Coretable

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCoretable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('coretable', function (Blueprint $table) {
            $table->bigIncrements('id_coretable');
            $table->string('Internal_key')->nullable(false)->unique();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('coretable');
    }
}

extensiontable_it c

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateExtensiontableItc extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('extensiontable_itc', function (Blueprint $table) {
            $table->bigIncrements('id_extensiontable_itc');
            $table->bigInteger('coretable_id')->unsigned()->unique()->nullable(false);
            $table->foreign('coretable_id', 'fk_extensiontable_itc_coretable')->references('id_coretable')->on('coretable');
            $table->string('description_itc')->nullable(false);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('extensiontable_itc');
    }
}

extensiontable_sysops

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ExtensiontableSysops extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('extensiontable_sysops', function (Blueprint $table) {
            $table->bigIncrements('id_extensiontable_sysops');
            $table->bigInteger('coretable_id')->unsigned()->nullable(false)->unique();
            $table->foreign('coretable_id', 'fk_extensiontable_sysops_coretable')->references('id_coretable')->on('coretable');
            $table->string('description_sysops')->nullable(false);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('extensiontable_sysops');
    }
}

1 Ответ

1 голос
/ 07 февраля 2020

SQLSTATE [42S22]: столбец не найден: 1054 Неизвестный столбец 'extensiontable_it c' in 'where clause' (SQL: update coretable set extensiontable_itc = {"description_it c" : "UPDATED1"}, coretable. updated_at = 2020-02-06 16:07:06 где extensiontable_itc = UPDATED1)

Вы не можете обновить данные отношений через with('relation')->update().

Я приведу пример для реализации этого на основе ваших файлов миграции.


Core

namespace App;

use App\ExtensiontableItc;
use App\ExtensiontableSysops;
use Illuminate\Database\Eloquent\Model;

class Core extends Model
{
    protected $table      = 'coretable';
    protected $primaryKey = 'id_coretable';
    protected $fillable   = [
        'id_coretable',
        'Internal_key',
    ];

    public function extensiontable_itc()
    {
        return $this->hasOne(ExtensiontableItc::class, 'coretable_id', 'id_coretable');
    }

    public function extensiontable_sysops()
    {
        return $this->hasOne(ExtensiontableSysops::class, 'coretable_id', 'id_coretable');
    }
}

ExtensiontableIt c

namespace App;

use Illuminate\Database\Eloquent\Model;

class ExtensiontableItc extends Model
{
    protected $table      = 'extensiontable_itc';
    protected $primaryKey = 'id_extensiontable_itc';
    protected $fillable   = [
        'coretable_id',
        'description_itc',
    ];
}

ExtensiontableSysops

namespace App;

use Illuminate\Database\Eloquent\Model;

class ExtensiontableSysops extends Model
{
    protected $table      = 'extensiontable_sysops';
    protected $primaryKey = 'id_extensiontable_sysops';
    protected $fillable   = [
        'coretable_id',
        'description_sysops',
    ];
}

Использование

$permittedTables = ['extensiontable_itc', 'extensiontable_sysops'];
$core            = Core::with($permittedTables)->find(1);

Вы получите (на основе ваш пример)

array:6 [
  "id_coretable" => 1
  "Internal_key" => "TESTKEY_1"
  "created_at" => "2020-02-07 18:05:50"
  "updated_at" => "2020-02-07 18:05:50"
  "extensiontable_itc" => array:5 [
    "id_extensiontable_itc" => 1
    "coretable_id" => 1
    "description_itc" => "UPDATED1"
    "created_at" => "2020-02-07 18:17:08"
    "updated_at" => "2020-02-07 11:32:44"
  ]
  "extensiontable_sysops" => array:5 [
    "id_extensiontable_sysops" => 1
    "coretable_id" => 1
    "description_sysops" => "UPDATED1"
    "created_at" => "2020-02-07 18:17:21"
    "updated_at" => "2020-02-07 11:32:44"
  ]
]

Чтобы обновить ваши отношения, вам нужно позвонить extensiontable_itc и extensiontable_sysops с просьбой загрузить через Core модель.


$input = [
    'id_coretable'          => 1,
    'Internal_key'          => 'TESTKEY_1',
    'extensiontable_itc'    => [
        'description_itc' => 'EXTENSION_ITC_1',
    ],
    'extensiontable_sysops' => [
        'description_sysops' => 'EXTENSION_SYSOPS_1',
    ],
];

$permittedTables = ['extensiontable_itc', 'extensiontable_sysops'];
$core            = Core::with($permittedTables)->find(1);

// Update extensiontable_itc
$core->extensiontable_itc->update($input['extensiontable_itc']);

// Update extensiontable_sysops
$core->extensiontable_sysops->update($input['extensiontable_sysops']);
...