updateOrInsert does not work well.when a record exist , it happens duplicate error
Error says
(PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2021-08-03 00:00:00-96' for key 'records.records_date_company_id_unique'
Record::updateOrInsert(
['company_id' => (int)$request->id
,'date' => $request->delivery_date
,'amount' => (int)$request->total_amount
,'created_at' => now()
]);
return response()->json($request, '200', ['Content-Type' => 'application/json','Charset' => 'utf-8'], JSON_UNESCAPED_UNICODE);
// I would like to add another response when it happens error
Migration define
class CreateRecordsTable extends Migration
{
public function up()
{
Schema::create('records', function (Blueprint $table) {
$table->dateTime('date');
$table->integer('company_id');
$table->Integer('amount');
$table->timestamps();
$table->unique(['date', 'company_id']);
});
}
The updateOrInsert method accepts two arguments: an array of conditions by which to find the record, and an array of column and value pairs indicating the columns to be updated.
In your case, it should look something like below:
Record::updateOrInsert(
['company_id' => (int) $request->id, 'date' => $request->delivery_date],
['amount' => (int) $request->total_amount]
);
I have two models: Departments and DepartmentTypes. In DepartmentTypes i have a column "depth" serving as foreign key to departments (field: hirarchy_lvl). That said, i am trying to get the DepartmentType label to be displayed in a view but keep on failing...
Here's what i have:
Department.php:
public function departmentType()
{
return $this->belongsTo(DepartmentType::class, 'depth', 'hirarchy_lvl');
}
DepartmentType.php
public function department()
{
return $this->hasMany(Department::class, 'hirarchy_lvl', 'depth');
}
db schema create:
public function up()
{
Schema::create('department_types', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
$table->bigInteger('depth')->unsigned()->unique();
$table->string('hirarchy_lvl_name');
});
DB::table('department_types')->insert(array('created_at' => now(), 'depth' => '10', 'hirarchy_lvl_name' => 'company'));
DB::table('department_types')->insert(array('created_at' => now(), 'depth' => '20', 'hirarchy_lvl_name' => 'department'));
DB::table('department_types')->insert(array('created_at' => now(), 'depth' => '30', 'hirarchy_lvl_name' => 'team'));
DB::table('department_types')->insert(array('created_at' => now(), 'depth' => '40', 'hirarchy_lvl_name' => 'individual'));
Schema::table('departments', function (Blueprint $table) {
$table->foreign('hirarchy_lvl')->references('depth')->on('department_types')->onDelete('NO ACTION')->change(); //shall reference other objective
});
}
In the controller:
public function listDepartmentsByHirarchy($hirLvl = 0){
if($hirLvl){
$departments = Department::where('hirarchy_lvl', $hirLvl)->get();
}
else
{
$departments = Department::get();
}
$department_types = DepartmentType::get();
return view('configcenter/listDepartments', compact('departments', 'department_types'));
}
Testing in the view:
<td>
{{$department}}
</td>
gives me:
{"id":2,"created_at":"2019-12-18 13:04:11","updated_at":null,"description":"dep1","parent_dep":{"id":1,"created_at":"2019-12-18 13:04:11","updated_at":null,"description":"company","parent_dep":1,"hirarchy_lvl":10},"hirarchy_lvl":20}
Leading me to the conclusion that the foreign key does not get resolved properly (as it's just the value rather than the object i would need over here).
Now, after studying the documentation (https://laravel.com/docs/5.4/eloquent-relationships#has-many-through) and several posts, i cannot help myself but ask the noobish question: how do i reference the foreign key properly so i can work on the object in the view?
appreciate any hint...
Your Department::departmentType() relationship is incorrect, I believe. The fields should be switched.
When defining the belongsTo side of the relationship, the second parameter is the field on the defining model (departments.hirarchy_lvl) and the third parameter is the field on the related model (department_types.depth).
When defining the hasOne/hasMany side of the relationship, it is the opposite. The second parameter is the field on the related model, and the third parameter is the field on the defining model.
Department.php:
public function departmentType()
{
return $this->belongsTo(DepartmentType::class, 'hirarchy_lvl', 'depth');
}
DepartmentType.php
public function department()
{
return $this->hasMany(Department::class, 'hirarchy_lvl', 'depth');
}
I have 3 tables, the schema is below.
Employees,
EmployeeDB.php
$factory->define(Employee::class, function (Faker $faker) {
return [
'emp_id' => $faker->randomDigit,
'name' => $faker->name,
'dept_id' => $faker->numberBetween($min = 1, $max = 15),
'salary_id' => $faker->randomDigit(),
'gender' => $faker->randomElement(['M', 'F', 'T']),
/*if I remove these next 2 statements, I receive an error for
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'employee_id' in 'field list' (SQL: insert into `employees` (`emp_id`, `name`, `dept_id`, `salary_id`, `gender`, `date_of_joining`,
`date_of_birth`, `employee_id`, `updated_at`, `created_at`) values (2, Jamaal Beer, 3, 9, T, 2018-05-05 18:59:40, 2005-07-05 13:17:23, ?,
2019-12-11 11:15:42, 2019-12-11 11:15:42))
*/
'employee_id' => $faker->randomDigit,
//Same for this one as well
'department_id' => $faker->randomDigit,
'date_of_joining' => $faker->dateTimeBetween($startDate = '-5 years', $endDate = 'now', $timezone = null),
'date_of_birth' => $faker->dateTimeBetween($startDate = '-20 years', $endDate = 'now', $timezone = null),
Employee Migration table:
Schema::create('employees', function (Blueprint $table) {
$table->bigIncrements('emp_id');
$table->integer('dept_id')->unsigned();
$table->foreign('dept_id')->references('id')->on('departments');
$table->integer('salary_id')->unsigned();
$table->foreign('salary_id')->references('id')->on('salaries');
$table->string('name');
$table->string('gender');
$table->timestamp('date_of_joining');
$table->dateTime('date_of_birth');
/*SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'employee_id' cannot be null
(SQL: insert into `employees` (`emp_id`, `name`, `dept_id`, `salary_id`, `gender`, `employee_id`, `department_id`,
`date_of_joining`, `date_of_birth`, `updated_at`, `created_at`)
values (6, Martina Wuckert, 7, 3, F, ?, 3, 2018-09-14 05:59:15, 20
*/
$table->string('employee_id')->nullable();
$table->string('department_id')->nullable();
$table->timestamps();
//added to prevent errors
Departments
DepartmentsDB.php
factory->define(Department::class, function (Faker $faker) {
return [
//Yes, this is a hack. Use Multidimensional Arrays the next time.
'id' => $faker->numberBetween($min = 1, $max = 15),
'dept_name' => $faker->randomElement(['Production', 'Purchase & Quality', 'Operations', 'Sales', 'Customer Serice', 'Business Development', 'Maketing', 'Tech Support', 'Finance', 'Human Resources', 'Research & Development', 'IT', 'Legal']),
];
DepartmentsMigration
Schema::create('departments', function (Blueprint $table) {
$table->increments('id');
$table->string('dept_name');
$table->timestamps();
});
Salaries
SalaryDb.php
$factory->define(Salary::class, function (Faker $faker) {
return [
'id' => $faker->randomDigit(),
'monthlySalary' => $faker->randomNumber($nbDigits = 3),
//Yes this is a hack. Use MultiDimensional Arrays the next time.
];
});
SalariesMigration
$factory->define(Salary::class, function (Faker $faker) {
return [
'id' => $faker->randomDigit(),
'monthlySalary' => $faker->randomNumber($nbDigits = 3),
//Yes this is a hack. Use MultiDimensional Arrays the next time.
];
});
App\Department
class Department extends Model
{
//
public function employee()
{
return $this->hasMany(Employee::class);
}
public function salary()
{
return $this->hasMany(Salary::class);
}
}
App\Employee
class Employee extends Model
{ //belongsto block
public function department()
{
return $this->hasOne(Department::class);
}
public function Salary()
{
return $this->hasOne(Salary::class);
}
}
App\Salary
class Salary extends Model
{
//
public function employee()
{
return $this->belongsTo(Employee::class);
}
}
DatabaseSeeder.php
factory(App\Employee::class, 25)->create()->each(function ($employee) {
$department = factory(App\Department::class)->make();
$employee->department()->save($department);
$salary = factory(App\Salary::class)->make();
$employee->salary()->save($salary);
});
When I run the below command, this is the error I get
php artisan db:seed
Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`volga_2`.`employees`, CONSTRAINT `employees_dept_id_foreign` FOREIGN KEY (`dept_id`) REFERENCES `departments` (`id`))")
What I am trying to do is: for every Employee Record, One Department and One Salary is assigned.
This is for later: Departments cannot be duplicated within its own table. Ie. Once a department id with name is created, it cannot be recreated again.
I know I am going wrong, else there wouldn't be errors. When I run the dbSeeder for departments and salaries, it works fine. But whenever there is a duplicate department entry it throws up an error. But the data stored in the db is fine.
I would like a solution or a few pointers, because I'm still learning Laravel.
Thanks!
EDIT
When I execute
php artisan migrate
Order of Migrations
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.44 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (1.18 seconds)
Migrating: 2019_12_09_105432_create_departments_table
Migrated: 2019_12_09_105432_create_departments_table (0.29 seconds)
Migrating: 2019_12_09_105743_create_salaries_table
Migrated: 2019_12_09_105743_create_salaries_table (0.21 seconds)
Migrating: 2019_12_10_104739_create_employees_table
Migrated: 2019_12_10_104739_create_employees_table (2.04 seconds)
Just change the order of the migrations. I am guessing you are trying to make relation before the table created. Make the first migration of the parent table
Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`volga_2`.`employees`, CONSTRAINT `employees_dept_id_foreign` FOREIGN KEY (`dept_id`) REFERENCES `departments` (`id`))")
this error says that it cant generate relation with departments table for some reason. as you write, you try to generate Employee with relation to 2 other table before generate them, by changing name of your migration, you can reorder migration. that means you can change order of running your migration with changing time in migration name so that you migrate with this order:
1) DepartmentsMigration
2) SalariesMigration
3) Employee Migration
Thank you all for providing solutions and ideas to help me solve this issue. But after tinkering with it, I worked out a solution that works fine.
I will just be posting the changes i made to keep it easier to keep a track of and it may be of help to someone else.
Here it is.
EmployeeDB.php
$factory->define(Employee::class, function (Faker $faker) {
return [
'emp_id' => $faker->unique()->randomNumber($nbDigits = 3, $strict = true),
'name' => $faker->name,
//dept_id and salary_id pulls the data from their respective tables and then //randomly assigns an id from the id column
'dept_id' => App\Department::all()->random()->id,
'salary_id' => App\Salary::all()->random()->id,
'gender' => $faker->randomElement(['M', 'F', 'T']),
'date_of_joining' => $faker->dateTimeBetween($startDate = '-5 years', $endDate = 'now', $timezone = null),
'date_of_birth' => $faker->dateTimeBetween($startDate = '-20 years', $endDate = 'now', $timezone = null),
];
});
EmployeeMigration
public function up()
{
Schema::create('employees', function (Blueprint $table) {
$table->unsignedInteger('emp_id', true);
$table->unsignedInteger('dept_id');
$table->foreign('dept_id')->references('id')->on('departments');
$table->unsignedInteger('salary_id');
$table->foreign('salary_id')->references('id')->on('salaries');
$table->string('name');
$table->string('gender');
$table->timestamp('date_of_joining');
$table->dateTime('date_of_birth');
$table->timestamps();
//added to prevent errors
});
Departmentdb
$factory->define(Department::class, function (Faker $faker) {
return [
//Yes, this is a hack. Use Multidimensional Arrays the next time.
'id' => $faker->unique()->numberBetween(1, 12),
'dept_name' => $faker->randomElement(['Production', 'Purchase & Quality', 'Operations', 'Sales', 'Customer Serice', 'Business Development', 'Maketing', 'Tech Support', 'Finance', 'Human Resources', 'Research & Development', 'IT', 'Legal']),
];
});
DepartmentMigration
protected $dept_id = 'id';
public function up()
{
Schema::create('departments', function (Blueprint $table) {
$table->unsignedInteger('id', true);
$table->string('dept_name');
$table->timestamps();
});
}
SalaryDB
$factory->define(Salary::class, function (Faker $faker) {
return [
'id' => $faker->unique()->randomNumber($nbDigits = 5, $strict = true),
'monthlySalary' => $faker->randomNumber($nbDigits = 3),
//Yes this is a hack. Use MultiDimensional Arrays the next time.
];
});
Salary Migration
public function up()
{
Schema::create('salaries', function (Blueprint $table) {
$table->unsignedInteger('id', true);
$table->string('monthlySalary');
$table->timestamps();
});
}
DatabaseSeeder.php
public function run()
{
$this->call([UsersTableSeeder::class]);//this is not important
factory('App\Department', 12)->create();
factory('App\Salary', 50)->create();
factory('App\Employee', 55)->create();
}
}
What is happening is that, I first seeded the Departments table, with the department ID's and their respective names. Then, I seeded, the salaries table, with just the salary id's and the salary amounts.
Then the employees seeder ran, which referenced the departments, and salaries table through the foreign key relations and inserted the data from the id columns in those respective tables into the dept_id and salary_id columns in my employees table.
Another important aspect to this, to set up the Primary Key is using
protected $id = 'Primary Key Table name'
See DepartmentMigration code block above. This needs to be defined outside the scope of the up() function, and must be present wherever a primary key needs to be defined.
I have done this over 3 hours, working out each individual DB Seeder, so I am happy this works. There is possibly a better more elegant solution out there, but I will get on to that tomorrow. :)
Thank you for reading, and I hope that this has help you.
I will answer any questions regarding this to the best of my ability. :)
I have problem with my seeds. Here is my structure of my tables:
1.Complaints:
Schema::create('complaints', function (Blueprint $table) {
$table->uuid('id');
$table->unsignedInteger('origin_id');
$table->timestamps();
$table->primary('id');
});
2.Complaint_bill
Schema::create('complaint_bills', function (Blueprint $table) {
$table->uuid('complaint_id');
$table->string('symbol')->nullable();
$table->string('item_name');
$table->timestamps();
$table->primary('complaint_id');
$table->foreign('complaint_id')->references('id')-
>on('complaints');
Now I have seeds :
factory(Complaint::class, 10)->create()->each(function ($c) {
$product = Product::inRandomOrder()->first();
factory(ComplaintBill::class, 10)->create([
'complaint_id' => $c->id,
'item_id' => $product->id,
'item_name' => $product->name,
'item_numeric_index' => $product->numeric_index,
'item_gross_price' => $product->sell_price_gross,
]);
})'
I have problem/error like this:
SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value
violates u
nique constraint "complaint_bills_pkey"
DETAIL: Key (complaint_id)=(ea302ab8-67dc-3bed-afc8-4215a99f1f68)
already exists.
When I comment primary in Complaint_bill ( column - complaint_id )then everything is ok. It looks like the problem is that I have primary key on uuid on Complaint_bill, which is foregin on Complaint->id. Why it is doing like this? I can't have primary on foregin when I have relation with two primary's?
The reason you are seeing this issue is that a UUID is not an auto-incrementing value in the traditional sense that an INTEGER AUTO_INCREMENT is when defining a primary key. When using factory methods to insert a set of data, the value doesn't "go up by one" automatically on each insert.
You would need to initialise each model generated with a boot function to generate the UUID for yourself prior to storage. From the below article:
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->{$model->getKeyName()} = Uuid::generate()->string;
});
}
The below article explains it in a bit more detail.
https://medium.com/#steveazz/setting-up-uuids-in-laravel-5-552412db2088
Try this: \Ramsey\Uuid\Uuid::uuid4()->toString()
`DB::table('customers')->insert([
['id' => \Ramsey\Uuid\Uuid::uuid4()->toString(), 'name' => 'Test', 'color' => '#aaa', 'created_at' => $now],
]);`
This is pretty weird and I have no idea what i'm doing wrong.
I have 2 models:
class Project extends Eloquent {
public function status()
{
return $this->belongsTo('ProjectStatus','status_id');
}
}
and
class ProjectStatus extends Eloquent {
protected $table = 'PStatus';
public function projects()
{
return $this->hasMany('Project');
}
}
The table "projects" has the proper foreign keys:
Schema::create('PStatus', function($table) {
$table->increments('id');
$table->string('name', 64);
$table->unique('name');
});
Schema::create('Projects', function($table) {
$table->increments('id');
$table->string('name', 100);
$table->integer('status_id')->unsigned();
$table->foreign('status_id')->references('id')
->on('PStatus')
->onDelete('cascade');
});
In the database (for example) I have only 1 project: "Project_1" (id = 1) with status_id = 1 (Lets say status name = "Open"). If I execute the following query:
$projects = Project::with(array('status' => function($query){
$query->where('name', '<>', 'Open');
}))->get();
I'm still getting the project in the results!!. This is the sql log:
array (size=3)
'query' => string 'select * from `PStatus` where `PStatus`.`id` in (?) and `name` <> ?' (length=67)
'bindings' =>
array (size=2)
0 => int 1
1 => string 'Open' (length=4)
'time' => float 0.36
if I print:
var_dump($projects->count());
I still get 1 project! How come?
I can easily solve my problem by changing the query to something like:
$projects = Project::where('status_id', '<>', 1)->get(); //assuming that status_id=1 => "Open"
but i prefer not to use ids directly when I guess the method with should work. What am I doing wrong here???
Actually this is the answer:
Eloquent Nested Relation with Some Constraint
A huge confusion with the with method. I should have used a join.