问题
I have the following input from the user:
array (
'id_coretable' => 1,
'Internal_key' => 'UPDATED1',
'extensiontable_itc' =>
array (
'description_itc' => 'UPDATED1',
),
'extensiontable_sysops' =>
array (
'description_sysops' => 'UPDATED1',
),
)
and its contents shall update the following model:
array (
'id_coretable' => 1,
'Internal_key' => 'TESTKEY_1',
'extensiontable_itc' =>
array (
'description_itc' => 'EXTENSION_ITC_1',
),
'extensiontable_sysops' =>
array (
'description_sysops' => 'EXTENSION_SYSOPS_1',
),
)
This model was created with this code:
$joinAsArray = coretable::with($permittedTables)->find(1);
Where $permittedTables
is an array of tablenames which determine the tables to be joined with coretable.
Now, I've spent multiple hours on pondering how to properly loop over a model, and it simply isnt possible without serializing the model to a plain array or the like. This doesnt really help though, since I want to UPDATE the model here, and if I just convert it to an array, then I lose this connection to the DB/Model.
So I'm now using a different approach. I'm looping the userinput, which will ALWAYS have the same structure and indexes as the model. And then I'm using the keys from the very well loopable userinputarray and a copy of the old model in form of an array, to determine the attributes of the model which shall be updated with the respective input data. This is what my code currently looks like:
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]);
}
}
Now, this code works pretty neatly for the outer array. I can indeed update the "Internal_key" field this way. However, once we hit the point where the joined table is represented in form of the "nested array", things go south. I get the following error message:
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)
I can kind of see where this comes from. Its trying to find a column extensiontable_itc
on coretable which obviously isnt there since it is its own relation, only connected to the coretable via FK.
The first thing that comes to my mind to deal with this problem is calling another model by dynamically inserting its name via the $key. Then I would have to loop over the nested arrays keys and values, basically doing the same thing as I did with the outer array.
This probably will consume a comparatively horrible amount of ressources, but this software is for internal purposes only and our DB-server probably will be able to handle this load. Its also quite hacky, I think^^
So, can anyone else give me another, more elegant, less ressource hungry and less hacky solution than mine?
EDIT: As per request in the comments, here are my migrations:
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_itc
<?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:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'extensiontable_itc' in 'where clause' (SQL: update
coretable
setextensiontable_itc
= {"description_itc":"UPDATED1"},coretable
.updated_at
= 2020-02-06 16:07:06 whereextensiontable_itc
= UPDATED1)
You can't update relation data via with('relation')->update()
.
I will make an example to implement this, based on your migration files.
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');
}
}
ExtensiontableItc
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',
];
}
Usage
$permittedTables = ['extensiontable_itc', 'extensiontable_sysops'];
$core = Core::with($permittedTables)->find(1);
You will get (based on your example)
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"
]
]
To update your relation, you need to call extensiontable_itc
and extensiontable_sysops
eager load via Core
model.
$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']);
来源:https://stackoverflow.com/questions/60099351/how-to-dynamically-build-this-query-laravel-lumen