Laravel 5.8 : Always give multiple primary key syntax or access violation error - eloquent

I have created migration file with composite primary key but always gives an error
syntax error or access violation : 1068 multiple primary key defined (sql : alter table 'table_currency' add primary key table_currency_code_user_id_primary('code', 'user_id'))
Schema::create('table_currency', function (Blueprint $table) {
$table->string('code', 3);
$table->bigIncrements('user_id');
$table->string('default', 3);
$table->enum('is_active', ['0','1'])->default('0')->comment('0: Inactive, 1: Active');
$table->timestamps();
$table->primary(['code', 'user_id']);
});
I don't get it why i got this error ? Thanx in advance.

If you want to make a composite primary key on ['user_id', 'code'] you need to remove the primary attached on your increments column. You can do this with this code:
Schema::create('table_currency', function (Blueprint $table) {
$table->bigIncrements('user_id'); // Has a primary key
$table->dropPrimary('table_currency_user_id_primary'); // Remove the primary key from the increments column
$table->primary(['code', 'user_id']); // Set your composite primary key
$table->string('code', 3);
$table->string('default', 3);
$table->enum('is_active', ['0','1'])->default('0')->comment('0: Inactive, 1: Active');
$table->timestamps();
});

Related

No unique constraint for composite foreign key, PostgreSQL

I am trying to relate an assosciative table with another table.
...
knex.schema.createTable("test", (table) => {
table.integer("subject_id").unsigned().references("id").inTable("subject").notNullable();
table.integer("duration_id").unsigned().references("id").inTable("duration").notNullable();
table.unique(["subject_id", "duration_id"]);
}),
knex.schema.createTable("exam", (table) => {
table.increments().notNullable();
table.integer("subject_id").unsigned();
table.integer("duration_id").unsigned();
...
...
table.foreign(["subject_id", "duration_id"]).references(["subject_id", "duration_id"]).inTable("test");
}),
...
throws the following error:
migration failed with error: alter table "exam" add constraint "exam_subject_id_duration_id_foreign" foreign key ("subject_id", "duration_id") references "test" ("subject_id", "duration_id")
- there is no unique constraint matching given keys for referenced table "test"
Having unique or primary key constraint for the two columns results in the same error. Is this a knex related error?
Moving the foreign key constraint after the unique constraint fixed the problem. Though I don't know the exact reason.
...
knex.schema.createTable("test", (table) => {
table.integer("subject_id").unsigned().notNullable();
table.integer("duration_id").unsigned().notNullable();
table.unique(["subject_id", "duration_id"]);
table.foreign("subject_id").references("id").inTable("subject");
table.foreign("duration_id").references("id").inTable("duration");
}),
knex.schema.createTable("exam", (table) => {
table.increments().notNullable();
table.integer("subject_id").unsigned();
table.integer("duration_id").unsigned();
...
...
table.foreign(["subject_id", "duration_id"]).references(["subject_id", "duration_id"]).inTable("test");
}),
...

Eloquent default attribute values: $attributes or DB column default value?

What's the proper way to implement default values for Eloquent models?
I've configured my database tables using Laravel's migrations. Some columns have default values specified. When using these tables in conjunction with Eloquent models, different things happen depending on the selected database driver:
In MySQL, when creating a new model and saving it, a DB row is inserted having the column's default value for every attribute that was not explicitly specified. This is what I would like to happen.
In Postgres and SQLite however, this is not the case. A PDOException is thrown:
[PDOException]
SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column
"some_column" violates not-null constraint
DETAIL: Failing row contains (1, 2, 3, 4, 5, 6, null, null, null, null, null, null, 7, 8, null, 9, null, null, 10, 11, 12, null).
It is clear to me that the column is not nullable and that null values are not accepted. I would expect however that the default value was inserted instead of an error being raised.
I would suggest that you create your own parent model that extends Eloquent directly, and have all of your models extend this custom parent.
In the custom parent, override the performInsert() method to remove null values just before inserting. Be sure to copy the entire method from the Eloquent source code so you don't lose any important steps in the process:
class MyModelParent extends Illuminate\Database\Eloquent\Model
{
/**
* Perform a model insert operation.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return bool
*/
protected function performInsert(Builder $query)
{
if ($this->fireModelEvent('creating') === false) {
return false;
}
... // Be sure to copy all of it!
// This is the change you'll make. Before, it was just:
// $attributes = $this->attributes;
$attributes = array_filter($this->attributes, function($val){
return $val !== null;
});
... // Be sure to copy all of it!
return true;
}
}
performUpdate() should handle this issue fine, since it uses getDirty() to get the list of fields instead of accessing the property directly.
And while you're at it, you should consider submitting a patch to Laravel that would make the core Postgres-safe.
SQL NOT NULL Constraint
The NOT NULL constraint enforces a column to NOT accept NULL values.
you are adding a null value on NOT NULL column
it seems
http://www.w3schools.com/sql/sql_notnull.asp

Adding column with foreign key into table.

I have some problem. I want to add new column into my table that references to other column in other table. I do something like that:
class m161202_153033_dodanie_informacji_o_obsludze_prawnej_do_pozyczki extends CDbMigration
{
public function safeUp()
{
$this->execute("ALTER TABLE loan ADD COLUMN administrator int NOT NULL DEFAULT 15 REFERENCES person (id) ON UPDATE CASCADE ON DELETE NO ACTION;");
}
public function safeDown()
{
$this->execute("ALTER TABLE loan DROP COLUMN administrator;");
}
}
But when i try to execute this migration i have this error:
Foreign key violation: 7
DETAIL: Key (administrator)=(15) doesn't appear in table "person"..
I know that there is no suck column "administrator" in my table. But i want to add new column "administrator" into loan table. I wanted to make "administrator" foreign key from person table, column "id". Can u help me, what am i doing wrong?
The error means that there is no row in person with id equal to 15, which would be required for the constraint to be fulfilled.
When you run that ALTER TABLE statement, the table has to be rewritten, and the new column is filled with the value 15.
Often it is easier to create a new column nullable and without default value (then ALTER TABLE will not rewrite the table) and use UPDATE to populate the new column. After that you can change the column definition to NOT NULL and add a default value.
Try this
class m161202_153033_dodanie_informacji_o_obsludze_prawnej_do_pozyczki extends CDbMigration
{
public function safeUp()
{
$this->execute("INSERT INTO person (id) VALUES (15) ON CONFLICT (id) DO NOTHING;");
$this->execute("ALTER TABLE loan ADD COLUMN administrator int NOT NULL DEFAULT 15 REFERENCES person (id) ON UPDATE CASCADE ON DELETE NO ACTION;");
}
public function safeDown()
{
$this->execute("ALTER TABLE loan DROP COLUMN administrator;");
}
}

dead-lock scenario in grails when trying to do ORM

I am writing a simple grails (2.3.1) sample application which uses postgresql(9.1)
I have two domain classes 'Nose' and 'Face'.
//Nose class
package human
class Nose {
static belongsTo=[face:Face]
static constraints = {
face nullable: true
}
}
//Face class
package human
class Face {
static hasOne = [nose:Nose];
static constraints = {
nose nullable: true
}
}
My database is empty and I am using static scaffold.
Now, grails does not allow me to insert into either, because one has foreign key constraint with other.
Also, when i try to insert directly in the postgresql database, i get the same foreign key constraint error:
human=# insert into nose (id, version, face_id) values (1, 0, 1);
ERROR: insert or update on table "nose" violates foreign key constraint "fk33afd3c47bf8db"
DETAIL: Key (face_id)=(1) is not present in table "face".
OR
human=# insert into face (id, version, nose_id) values (1, 0, 1);
ERROR: insert or update on table "face" violates foreign key constraint "fk2fd65d8476fd1b"
DETAIL: Key (nose_id)=(1) is not present in table "nose".
human=#
How to resolve this dead-lock condition ?

EntityFramework - many-to-many reference in the DB without a backreference in the model

In my application users can define Parameters, and then create SlideSets based on a grouping of parameters.
I am using code-first Entity Framework 5.0 and I have the following model:
class SlideSet {
public ICollection<Parameter> Parameter
}
class Parameter {}
A parameter might be used by many slidesets or none at all. However, in my domain a parameter has no need to reference a SlideSet, they are in separate bounded contexts (both SlideSet and Parameter are Aggregate Roots). As such, I don't want to put a reference from Parameter to SlideSet.
The table model (I don't care about table/column names) that I want is
Table SlideSet
Table Param
Table SlideSetParam
FK_SlideSet
FK_Param
I know I could model this by introducing a ParameterGroup entity or a Param.SlideSets collection, but it would exist solely for ORM mapping purposes (and cause serialization issues). Is there any other way to tell EF to generate this table model from my entities?
This should make you a Parameter w/o a navigation property:
modelBuilder.Entity<SlideSet>()
.HasMany(x => x.Parameters)
.WithRequired();
EDIT:
Based on the comment - that should be all together similar. This seems to work nicely what you're trying to do....
modelBuilder.Entity<SlideSet>()
.HasMany(x => x.Parameters)
.WithMany();
...and you can use it either way:
var slideset = new SlideSet { Parameters = new []
{
new Parameter{},
new Parameter{},
new Parameter{},
new Parameter{},
}
};
var slideset2 = new SlideSet { };
db.SlideSets.Add(slideset);
db.SaveChanges();
var slidesets = db.SlideSets.ToList();
var parameters = db.Parameters.ToList();
Console.WriteLine("");
db.SlideSets.Add(slideset2);
db.SaveChanges();
slidesets = db.SlideSets.ToList();
parameters = db.Parameters.ToList();
Console.WriteLine("");
...and the SQL:
CREATE TABLE [dbo].[Parameters] (
[ParameterID] [int] NOT NULL IDENTITY,
CONSTRAINT [PK_dbo.Parameters] PRIMARY KEY ([ParameterID])
)
CREATE TABLE [dbo].[SlideSets] (
[SlideSetID] [int] NOT NULL IDENTITY,
CONSTRAINT [PK_dbo.SlideSets] PRIMARY KEY ([SlideSetID])
)
CREATE TABLE [dbo].[SlideSetParameters] (
[SlideSet_SlideSetID] [int] NOT NULL,
[Parameter_ParameterID] [int] NOT NULL,
CONSTRAINT [PK_dbo.SlideSetParameters] PRIMARY KEY ([SlideSet_SlideSetID], [Parameter_ParameterID])
)
CREATE INDEX [IX_SlideSet_SlideSetID] ON [dbo].[SlideSetParameters]([SlideSet_SlideSetID])
CREATE INDEX [IX_Parameter_ParameterID] ON [dbo].[SlideSetParameters]([Parameter_ParameterID])
ALTER TABLE [dbo].[SlideSetParameters] ADD CONSTRAINT [FK_dbo.SlideSetParameters_dbo.SlideSets_SlideSet_SlideSetID] FOREIGN KEY ([SlideSet_SlideSetID]) REFERENCES [dbo].[SlideSets] ([SlideSetID]) ON DELETE CASCADE
ALTER TABLE [dbo].[SlideSetParameters] ADD CONSTRAINT [FK_dbo.SlideSetParameters_dbo.Parameters_Parameter_ParameterID] FOREIGN KEY ([Parameter_ParameterID]) REFERENCES [dbo].[Parameters] ([ParameterID]) ON DELETE CASCADE
...this makes the original tables practically 'agnostic' of the relationships (many-to-many) - while index table is automatically generated in the background.
You can also further customize that and make your own SlideSetParam (e.g. if you'd want to add additional fields there) with pretty much the same layout - just Parameters would have to point to that instead.