Can't store a new row - SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails - mysql

My clients table and users table are child tables of my businesses table. So both the clients and users table contain a business_id column that refers to the id column of the businesses table:
public function up()
{
Schema::create('clients', function(Blueprint $table)
{
$table->increments('id');
$table->integer('business_id')->unsigned();
$table->foreign('business_id')->references('id')->on('businesses');
$table->string('first_name');
$table->string('last_name');
Etc…
I am able to store a new user, it works fine, but I keep getting this error when trying to store a new row into my clients table :
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(laravel.clients, CONSTRAINT clients_business_id_foreign FOREIGN
KEY (business_id)
Client.php model
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['business_id', 'first_name', 'last_name'];
/**
* Business where this user works.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function businesses()
{
return $this->belongsTo('App\Business');
}
Business.php model
/**
* Clients that use this business.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function clients()
{
return $this->hasMany('App\Client','business_id');
}
ClientsController.php
public function store(ClientsRequest $request)
{
var_dump(Auth::user()->business_id);
$clientinfo = Request::all();
Client::create($clientinfo);
$client = new Client;
$client->business_id = Auth::user()->business_id;
$client->first_name = $clientinfo['first_name'];
$client->last_name = $clientinfo['last_name'];
//$client->save();
$business->clients()->save($client);
$last_inserted_id = $data->id;
return redirect('clients/'.$last_inserted_id.'/edit');
The only thing I’m not sure is the way I’m retrieving the business_id (from the users table), via Auth. When I var_dump that value, I get :
string(1) "7"
I know the id value is 7 in my businesses table, that’s what I’m looking for, but not sure if it should be converted to integer.
And, not sure if I have to save using :
$client->save();
Or
$business->clients()->save($client);
Thanks

Both following are correct ways, but first one is more Laravel than later,
public function store(ClientsRequest $request)
{
$client = new Client([
'first_name' => $request->get('first_name'),
'last_name' => $request->get('last_name'),
]);
$client = Business::findOrFail(Auth::user()->business_id)
->clients()
->save($client);
return redirect('clients/'.$client->id.'/edit');
}
P.S. above business_id will be automatically added to client by Eloquent
Other way is like you did, where you are inserting a business_id manually.
public function store(ClientsRequest $request)
{
$clientinfo = Request::all();
$client = Client::create([
'business_id' => Auth::user()->business_id;
'first_name' => $clientinfo['first_name'];
'last_name' => $clientinfo['last_name'];
]);
return redirect('clients/'.$client->id.'/edit');
}
You are receiving error because of following statement in your code,
Client::create($clientinfo);
Above statement will attempt to create a database entry without business_id which is a foreign key and should be supplied but wasn't and hence error.
And you don't have to worry about type-conversion between int<->string, PHP is very good at it.
Read More

Related

SQLSTATE[42000]: Syntax error or access violation: 1055 when using groupBy with hasManyThrough relation in Laravel

When using groupBy on hasMany relation it is work fine but
when using groupBy on hasManythrough relation
in my controllr :
public function main()
{
# code...
$user = Auth::user();
$results = [
'vacations' => $user->vacations()->groupBy('type')->selectRaw('sum(days) as days,sum(mins) as mins, type')->get(), //works fine
'vactionRegisterd' => $user->vacationsRegisterd()->groupBy('type')->selectRaw('sum(days) as days,sum(mins) as mins, type')->get(), //works fine
'empVacations'=>$user->empVacations, //work fine
'employees_vacations'=>$user->empVacations()->groupBy('type')->selectRaw('sum(days) as days,sum(mins) as mins, type')->get(),//gives an error
];
return view('dashboard.dashboard', ['results' => $results]);
}
I have this error :
SQLSTATE[42000]: Syntax error or access violation: 1055
'hrweb.users.manager_id' isn't in GROUP BY (SQL: select sum(days) as
days,sum(mins) as mins, type, users.manager_id as
laravel_through_key from vacations inner join users on
users.id = vacations.user_num where users.manager_id = 5
group by type)I have tow tables users ,vacations
I don't know why (users.manager_id as laravel through key) is used even though I didn't use "users.manager_id" with "groupBy" or "selectRow" method.
My Code in user model :
1- user has many employees where employees are also users with different role and with manager_id != null [user->employees]
/**
* Get all of the employees from user table for the current admin User
*/
public function employees()
{
return $this->hasMany('App\Models\User', 'manager_id');
}
2- user has many vacations [user->vacations]
/**
* Get all of the vacations for the User
*/
public function vacations()
{
return $this->hasMany('App\Models\Vacations', 'user_num', 'id');
}
3- user hasManyThrough vacations [user->employees->vacation]
/**
* Get all of the employees vacations for the User
*/
public function empVacations()
{
return $this->hasManyThrough(Vacations::class, User::class, 'manager_id', 'user_num', 'id', 'id');
}
By reading the Error again ,I noted that Laravel use the foreign key as laravel_through_key in the query in some way.
The problem solved by adding laravel_through_key in the groupBy() method like this :
[...
'employees_vacations'=>$user->empVacations()
-> groupBy('laravel_through_key','user_num','type')
-> selectRaw('sum(days) as days,sum(mins) as mins,user_num, type')->get()
]
But I still think there is a better solution so I will be happy to know your answers ^_^

Laravel uses wrong primary key updating mysql

I set a custom string typed primary key in Laravel 6.x, calling
$node=Node::create() is fine, but when calling $node->save() later to update, it uses where ‘instanceId’=0 to match the primary key, which throw an exception with MySQL 1292 error.
For table schema (migrate):
public function up()
{
Schema::create('nodes', function (Blueprint $table) {
$table->string('instanceId')->primary();
$table->string('regionId')->nullable();
$table->string('privateIp')->unique()->nullable();
$table->string('publicIp')->unique()->nullable();
$table->string('dnsRecordId')->unique()->nullable();
$table->unsignedTinyInteger('status')->default(0);
$table->unsignedInteger('userId');
$table->timestamps();
});
}
For model definition:
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'instanceId';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'instanceId',
'regionId',
'privateIp',
'publicIp',
'dnsRecordId',
'status',
'userId',
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'userId' => 'integer',
];
Looks like you didn't set the value of instanceId before calling $node->save().
so it looks like $node->instanceId was null and since instanceId is a primary key it can't be null.
To prevent such issue, you need to set the value of instanceId before saving it or else you can set the default random value of the instanceId in the createSchema.
$node->instanceId = str_random(20);
Thanks
Thanks to lagbox, this is really a RTFM problem.
When using string primary key $incrementing=false and $keyType=‘string’ are required, otherwise Laravel will assume the primary key is self incrementing integer.

Laravel - Integrity constraint violation: 1452 Cannot add or update a child row

I am importing some content from remote WP database to local DB with laravel. I have set up the tables inventories and contents.
Inventories table looks like this:
Schema::create('inventories', function (Blueprint $table) {
$table->increments('id');
$table->integer('remote_id')->unsigned();
$table->integer('local_id')->unsigned();
$table->string('local_type');
$table->timestamps();
$table->foreign('local_id')->references('id')->on('contents')->onDelete('cascade');
});
This is the contents table:
Schema::create('contents', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->integer('ct_id')->unsigned();
$table->foreign('ct_id')->references('id')->on('content_types');
$table->integer('cms_id');
$table->string('title');
$table->string('slug');
$table->text('excerpt');
$table->mediumText('body');
$table->string('password');
$table->integer('parent_id');
$table->timestamps();
});
I have made functions to import all and import single posts from remote WP DB. This is the import for all posts:
public function all()
{
$include = array_diff($this->indexable, ['folder']);
$publishedPostsIDs = $this->import($include);
$this->deleteOldContent($publishedPostsIDs);
}
private function import($include)
{
$posts = Post::where('post_status', 'publish')->whereIn('post_type', $include)->get();
foreach ($posts as $post) {
$publishedPostsIDs[] = $post->ID;
$this->contentInterface->updateOrCreateInventory($post->ID);
}
return $publishedPostsIDs;
}
public function updateOrCreateInventory($remoteId)
{
$this->contentInterface->updateOrCreateInventory($remoteId);
}
private function deleteOldContent($publishedPostsIDs)
{
$contentToDelete = Content::whereNotIn('cms_id', $publishedPostsIDs)->get();
if (count($contentToDelete) > 0) {
foreach ($contentToDelete as $content) {
$content->delete();
}
}
}
So, when I am importing all, I just go to the route that goes to all function, and all the posts from remote WP DB that are not of post type folder are imported. If I want to import a single post from remote DB, then I have a route that goes directly to the updateOrCreateInventory function. I also have import for the posts of type folder, which is basically almost the same as the function all.
public function folder()
{
$include = ['folder'];
$importResult = $this->import($include);
return $importResult['imported'];
}
The problem I have is that when I am importing all folders at once I get an error:
QueryException in Connection.php line 729: SQLSTATE[23000]: Integrity
constraint violation: 1452 Cannot add or update a child row: a foreign
key constraint fails (middleton.inventories, CONSTRAINT
inventories_local_id_foreign FOREIGN KEY (local_id) REFERENCES
contents (id) ON DELETE CASCADE) (SQL: insert into inventories
(remote_id, updated_at, created_at) values (7512, 2017-11-13
15:33:17, 2017-11-13 15:33:17))
But, if I try to import that same folder individually , or to be more exact that same post of type folder, I don't get any error and the post is imported. How is that possible?
You $this->contentInterface creates an Inventory model without the "local_id" field specified, but it is required by the foreign key.
Find the place where you create the Inventory model and provide a valid "local_id".

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

i have reply_qs table and postqs table.Postqs_id is foreign key in reply_qs table.when i tried to save the reply_qs form data in database,its showed this error.
ERROR:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a
child row: a foreign key constraint fails (fyp2.reply_qs, CONSTRAINT
reply_qs_postqs_id_foreign FOREIGN KEY (postqs_id) REFERENCES postqs
(id) ON DELETE CASCADE ON UPDATE CASCADE) (SQL: insert into reply_qs
(reply, updated_at, created_at) values (saann, 2017-09-22 15:35:03,
2017-09-22 15:35:03))
how i can solve it? and please explain why im getting this error.
reply_qs model :
protected $table = 'reply_qs';
protected $fillable = ['reply'];
public function postqs(){
return $this->hasMany('App\Postqs');
}
postqs model :
public function reply_qs(){
return $this->hasMany('App\Reply_qs');
}
store function:
public function store(Request $request){
$data = $request->all();
$postqs=($request->id);
$reply=Reply_qs::create($data);
$reply->postqs($id);
}
migration:
Schema::create('reply_qs', function (Blueprint $table) {
$table->increments('id')->unique();
$table->text('reply');
$table->timestamps('date');
});
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
Schema::table('reply_qs',function(Blueprint $table)
{
$table->integer('postqs_id')->unsigned();
$table->foreign('postqs_id')->references('id')->on('postqs') -
>onDelete('cascade')->onUpdate('cascade');
});
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
Your relationships are not correct.
Your Reply_qs model should have this relationship with Postqs
public function postqs()
{
return $this->belongsTo(Postqs::class);
}
Your store function does not look correct and should look something like this
public function store( Request $request )
{
$reply = new Reply_qs();
$reply->text = $request->get('text');
$reply->postqs_id = $request->get('postqs_id');
$reply->save();
}
In your store method, it looks like you are trying to associate the parent Postqs object with the Reply_qs.
You would do this like so
$reply->associate($post);
You need to pass the object and not the id
If you are still struggling with this double check your foreign keys are matching correctly, you may need to implement the association like so
public function postqs()
{
return $this->belongsTo(Postqs::class, 'postqs_id', 'id);
}

Foreign Key In MySQL using Yii

I have the database just like this
==== Invoices ====
id
costumer_id
description
==== Costumers ===
id
firstname
lastname
Now I have made the relation in between models just like this.In Invoices models the relation is as like this
public function relations()
{
return array(
'customer' => array(self::BELONGS_TO, 'Customer', 'customer_id')
);
}
In costumer model the relation is just like this
public function relations()
{
return array(
'invoice' => array(self::HAS_MANY, 'Invoices','customer_id')
);
}
Now as my relation is defined one costumer has many invoices and the invoice is belongs to the costumer.
Now I made multimodel and loaded the Costumer model into Invoice model just like this.
public function actionCreate()
{
$model = new Invoices;
$customers = new Customers;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if (isset($_POST['Invoices'],$_POST['Customers']))
{
$model->attributes = $_POST['Invoices'];
$customers->attributes = $_POST['Customers'];
$valid = $model->validate();
$valid = $customers->validate();
if($valid)
{
$model->save(false);
$customers->id = $model->customer_id;
$customers->save(false);
$this->redirect(array('view','id'=>$model->id));
}
}
$this->render('create',array(
'model'=>$model,
'customers'=>$customers,
));
}
Here every thing is okay. I can insert the data for both models easily. But my problem comes here in the way that when I am inserting data from Invoice multimodel the foreign key id is not changing. It is showing zero everytime. Can some one tell me where I am wrong.Any help and suggestions will be highly appriciable.
My guess is that you are overriding the customer's primary key with the invoice's foreign key. I do not say that's not correct that way (maybe in your scenario it makes sense).
Let me explain what you are doing in that code:
First, you create new instances of two models, Invoices and Customers. Yii understands that as "they wish to insert new items in the database".
Then, you check if there are the items coming from an ajax form. If true, then,
You populate Invoices (defined as $model. I'd change it to $invoice, in case you need to edit and understand it further).
You also popupulate the customer's information, overriding the $valid value (so, you don't know if invoice is actually valid).
If valid (remember you're only validating customer's information), do,
Save the invoice
Override customer's id with invoice's foreing key to customer.
Save the customer, and redirect.
Now, what I got from that:
$valid doesn't work as expected: I'd change that to an incremental assignment.
You may not be passing a customer_id coming from the ajax form. Foreing keys are integers, and so if not defined within a model, it becomes 0 or NULL.
You are always passing id = 0 / NULL to Customer's model, so it would probably warn you when validating. However, you are using save(false), which means it doesn't pre-validate on save, so you never know it doesn't work.
So, according to this:
public function actionCreate()
{
$invoice = new Invoices;
$customers = new Customers;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($invoice);
if (isset($_POST['Invoices'],$_POST['Customers']))
{
$invoice->attributes = $_POST['Invoices'];
$customers->attributes = $_POST['Customers'];
$valid = true; /* expect it is always valid */
$valid &= $invoice->validate(); /* if $invoice is not valid, $valid will be false (true&false = false) */
$valid &= $customers->validate(); /* same as the above line */
if($valid)
{
$customers->save(); /* First save customers. It's the Foreign item */
$invoice->customer_id = $customers->getPrimaryKey(); /* new instances use getPrimaryKey() to get its id */
$invoice->save(); /* Save invoice AFTER getting customer's primary key */
$this->redirect(array('view','id'=>$invoice->id));
}
}
$this->render('create',array(
'invoice'=>$invoice,
'customers'=>$customers,
));
}
I hope this solves your problem.
Please you need to understand a clear scenerio here. why would you use
if($valid)
{
$model->save(false);
$customers->id = $model->customer_id;
$customers->save(false);
$this->redirect(array('view','id'=>$model->id));
}
$model->save(false); tells model that if this record is not save(), the it shoud set the $customers->id = $model->customer_id;
This will only return false because. I do rather prefer if you call ( $customers->id = $model->customer_id;) before the $model->save();
REMEMBER, if you need to check if Save() returns true, then set it to $model->save(true)