cannot add or update a child row a foreign key constraint fails laravel factory - laravel

I have users table with 20 rows.
When I factored user_transaction table, I see this error.
Illuminate\Database\QueryException with message 'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fa
ils (webafra_testa.user_transaction, CONSTRAINT user_transaction_userid_foreign FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE) (SQL: inse
rt into user_transaction (userId, price, description, type, traceableId, receptorId, status, paymentMethod, tracking_code, created_at, update d_at) values (0, 5, Voluptatem assumenda facilis perferendis nihil est., money_transfer, 1, 1, waiting_payment, online, 1, 2021-05-29 10:41:30, 2021-05-29 10:41:30
))'
factory
$factory->define(UserTransaction::class, function (Faker $faker) {
return [
'userId' => $faker->randomKey([1, 20]),
'price' => $faker->randomDigit,
'description' => $faker->sentence(5),
'type' => $faker->randomElement(['order', 'sub_factor', 'money_transfer', 'increase_inventory', 'application_fee']),
'traceableId' => $faker->randomKey([1000, 9999]),
'receptorId' => $faker->randomKey([1000, 9999]),
'status' => $faker->randomElement(['done', 'canceled', 'waiting_payment']),
'paymentMethod' => $faker->randomElement(['tesseke', 'cash', 'online']),
'tracking_code' => $faker->randomKey([1000, 9999]),
'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
'updated_at' => Carbon::now()->format('Y-m-d H:i:s'),
];
});

'userId' => $faker->numberBetween(1, 20)
also for the others where you used randomKey , change it to numberbetween

Related

Write a new line arrow into a model_has_role_table Spatie Laravel

i am using Spatie in Laravel 8, I tried using eloquent but unfortunately there is no model for the tables created under the spatie migrations.
I am trying to excecute a line like this
DB::table('model_has_roles')->insert(['role_id' => 1, 'model_type' => 'App\Models\User' ,'model_id' => 4]);
i inserted this line into RegisterController.php in function create
protected function create(array $data)
{
DB::table('model_has_roles')->insert(['role_id' => 1, 'model_type' => 'App\Models\User' ,'model_id' => 4]);
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
When a register a new user i got the following error
Illuminate\Database\QueryException
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (tcsnpedro.model_has_roles, CONSTRAINT model_has_roles_role_id_foreign FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE) (SQL: insert into model_has_roles (role_id, model_type, model_id) values (1, App\Models\User, 4))
what does this error mean?
I found this interesting article Update database table column - Laravel
where a person do an update of the "model_has_roles" table, and i guess he succeeded doing this.
where should i put the following DB code?
DB::table('model_has_roles')->insert(['role_id' => 1, 'model_type' => 'App\Models\User' ,'model_id' => 4]);
Should i create a new laravel model in order to create and update information into the model_has_role spatie table?

How to fix upsert problem when seeding? (laravel)

I have these code below, all seems working but when I try to run unit test it returns an error below.
Here is my seeder (this seeder is called many times in different test cases):
DB::table('sizes')->upsert([
[
'name' => 'jumbo',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
],
[
'name' => 'large',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
]
], ['id'], ['name']);
And the errors pops out:
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: sizes.name (SQL: insert into "sizes" ("created_at", "name", "updated_at") values (2021-05-10 12:52:18, jumbo, 2021-05-10 12:52:18), (2021-05-10 12:52:18, large, 2021-05-10 12:52:18) on conflict ("id") do update set "name" = "excluded"."name")
Here is the migration:
Schema::create('sizes', function (Blueprint $table) {
$table->id();
$table->string('name')
->unique();
$table->timestamps();
});
Your migration will result in such table:
id INT AUTO_INCREMENT PRIMARY_KEY
name VARCHAR UNIQUE
created_at TIMESTAMP
updated_at TIMESTAMP
Your seeder when run first time will insert such records:
id
name
created_at
updated_at
1
jumbo
...
...
2
large
...
...
Now, based on laravel's documentation on upsert:
If you would like to perform multiple "upserts" in a single query, then you should use the upsert method instead.
The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table.
The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database.
The upsert method will automatically set the created_at and updated_at timestamps if timestamps are enabled on the model:
The important point is:
The method's first argument consists of the values to insert or update,
while the second argument lists the column(s) that uniquely identify records within the associated table.
The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database
That means, your command:
DB::table('sizes')->upsert([
[
'name' => 'jumbo',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
],
[
'name' => 'large',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
]
], ['id'], ['name']);
Will do this:
check if any record have id of (blank) => no record will match (so upsert will become insert instead)
insert into database, value name=jumbo, and insert into database, value name=large,
this second step will fail since there's already record on database that have name=jumbo (and another record with name=large)
remember that you have name VARCHAR UNIQUE constraint, and this second step violates the UNIQUE constraint
Instead, you should change your seeder into this:
DB::table('sizes')->upsert([
[
'name' => 'jumbo',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
],
[
'name' => 'large',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
]
], ['name'], ['created_at','updated_at']);
The edited version will do this:
check if any record have name of "jumbo"
no record will match initially (so upsert will become insert first time),
and for subsequent run will match (so upsert will become update for subsequent runs)

How to increment column with Laravel Eloquent updateOrCreate()?

Is it possible to return the model id from the request below ?
Bar::insert([
'foo_id' => Foo::updateOrCreate([
'code' => $row[0],
'name' => $row[1]
])->increment('count')->id
]);
I also tried this:
Foo::updateOrCreate([
'code' => $row[0],
'name' => $row[1]
], [
'count' => DB::raw('count + 1')
])->id
But it doesn't work at inserting because it count is not yet set.
HINT: There is a column named "count" in table "foos", but it cannot be referenced from this part of the query. (SQL: insert into "public"."foos" ("id", "name", "count") values (123, Hello, count+1) returning "id")
=== EDIT ===
With DB::raw('IFNULL(count,0) + 1'), I'm getting:
SQLSTATE[42703]: Undefined column: 7 ERROR: column "count" does not exist
LINE 1: ... ("code", "name", "count") values ($1, $2, IFNULL(count,0) +...
^
HINT: There is a column named "count" in table "foos", but it cannot be referenced from this part of the query. (SQL: insert into "public"."foos" ("code", "name", "count") values (123, Hello, IFNULL(count,0) + 1) returning "id")
Unfortunately I don't think this is possible to reference the count column only when the update happens (since this is what is happening here). You will need to take the roundabout way:
$model = Foo::firstOrNew([
'code' => $row[0],
'name' => $row[1]
]);
$model->count = ($model->exists ? $model->count : 0) + 1;
$model->save();
Here $model->exists will be true if the model was retrieved from the database or false if a new one was created.
Efficiency-wise firstOrCreate is what updateOrCreate does anyway so there's no query cost added
try using IFNULL
Foo::updateOrCreate([
'code' => $row[0],
'name' => $row[1]
], [
'count' => DB::raw('IFNULL(count,0) + 1')
])
if you want the id, try it like this:
$id=(Foo::updateOrCreate([
'code' => $row[0],
'name' => $row[1]
], [
'count' => DB::raw('IFNULL(count,0) + 1')
]))->id;
note: this is working on mysql, not PostgreSQL
you just need to set column auto-increment in database and not need set it column in your eloquent

laravel factory Illuminate/Database/QueryException with message 'SQLSTATE[HY000]:

the problem is that tinker is not wrapping the content in a string
Illuminate/Database/QueryException with message 'SQLSTATE[HY000]:
General error: 1364 Field 'address_line_2' doesn't have a default
value (SQL: insert into Test (name, gender, mobile_phone,
alternate_phone, status, address_line_1, updated_at,
created_at) values (emitchell, dariana66#hotmail.com, Kendra
Friesen, Ole Carter, Gennaro Hickle, Prof. Brandon Herman PhD,
2018-12-21 01:07:12, 2018-12-21 01:07:12))'
if I add the quotes manually to every value like
values ('emitchell', 'dariana66#hotmail.com', 'Kendra
Friesen', 'Ole Carter', 'Gennaro Hickle', 'Prof. Brandon Herman PhD',
'2018-12-21 01:07:12', '2018-12-21 01:07:12')
It works
how can I make the random content generate by tinker being in quotes?
I even use (string)
$factory->define(App\Test::class, function (Faker $faker) {
return [
'name' => (string)$faker->sentence(),
'gender' => (string)$faker->sentence(),
'mobile_phone' => (string)$faker->sentence(),
'alternate_phone' => (string)$faker->sentence(),
'status' => (string)$faker->sentence(),
'address_line_1' => (string)$faker->sentence(),
'address_line_2' => (string)$faker->sentence(),
'town_city' => (string)$faker->sentence(),
'postscode' => (string)$faker->sentence(),
'notes' => (string)$faker->sentence()
];
});
or examples from the github page
'name' => $faker-> sentence($nbWords = 6, $variableNbWords = true), // 'Sit vitae voluptas sint non voluptates.'
it wont output string values...
what is going on ?
You don't need to specify the data type, you just need to call the function
'name' => $faker->sentence(),

Laravel Backpackl - Request Unique Product and Nutrients

I'm having a problem with my application. I have a CRUD where I choose a product and assign it nutrients to it, currently I only have 5 nutrintes. I am registering the nutrient and its value correctly, the problem is when I register a nutrinte repeated, instead of showing me an error to the user saying that nutrinte already was, he tries to register and the stick in the bank.
I tried to use unique, being that it bar any nutrinente that I try to register, even if it is new in this product.
How do I check if this nutrinente already exists?
I'm using the Backpack package.
public function rules(){
return [
'nutrient_id' => 'required',
'portion' => 'required|numeric',
'amount' => 'required|numeric',
];
}
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-62' for key 'product_nutritional_facts_nutrient_id_product_id_unique' (SQL: insert into `product_nutritional_facts` (`nutrient_id`, `portion`, `amount`, `product_id`, `updated_at`, `created_at`) values (2, 11, 11, 62, 2018-12-14 22:22:41, 2018-12-14 22:22:41))
You need separate requests on store and update. Please check the manual: https://laravel.com/docs/5.7/validation
On store:
public function rules(){
$id = Input::all()['id'];
return [
'nutrient_id' => 'required|unique:product_nutritional_facts,nutrient_id,NULL,id,deleted_at,NULL' . $id, // remove deleted_at,NULL if you don't use soft deletes
'portion' => 'required|numeric',
'amount' => 'required|numeric',
];
}
On update:
public function rules(){
$id = Input::all()['id'];
return [
'nutrient_id' => 'required|unique:product_nutritional_facts,nutrient_id,' . $id,
'portion' => 'required|numeric',
'amount' => 'required|numeric',
];
}

Resources