In my database I have a view called my_view. I use the view to join it with another table my_table. Cause I don't now a way to map a view with the orm-mapper of SQLAlchemy, I mapped my_view like any other table. I give the primary-key in the relationship definition:
some_value = relationship("MyView", primaryjoin=my_view_id == MyView.id, useList=False)
This for fine, until I try to delete from my_table. The error is:
AssertionError: Dependency rule tried to blank-out primary key column 'my_view.id' on Instance '<MyView at 0x...>'
I am sure, the error happens, cause the mapper tries to delete a row from my_view. I found the cascade parameter, but I don't find out how I can stop it.
You can use the relationship option: passive_deletes="all"
See https://docs-sqlalchemy.readthedocs.io/ko/latest/orm/relationship_api.html#sqlalchemy.orm.relationship.params.passive_deletes
Additionally, setting the flag to the string value ‘all’ will disable
the “nulling out” of the child foreign keys, when there is no delete
or delete-orphan cascade enabled. This is typically used when a triggering
or error raise scenario is in place on the database side.
Related
Given the schema:
What I need is having every user_identities.belongs_to reference an users.id.
At the same time, every users has a primary_identity as shown in the picture.
However when I try to add this reference with ON DELETE NO ACTION ON UPDATE NO ACTION, MySQL says
#1452 - Cannot add or update a child row: a foreign key constraint fails (yap.#sql-a3b_1bf, CONSTRAINT #sql-a3b_1bf_ibfk_1 FOREIGN KEY (belongs_to) REFERENCES users (id) ON DELETE NO ACTION ON UPDATE NO ACTION)
I suspect this is due to the circular dependency, but how could I solve it (and maintain referential integrity)?
The only way to solve this (at least with the limited capabilities of MySQL) to allow NULL values in both FK columns. Creating a new user with a primary identity would then look something like this:
insert into users (id, primary_identity)
values (1, null);
insert into identities (id, name, belongs_to)
values (1, 'foobar', 1);
update users
set primary_identity = 1
where id = 1;
commit;
The only drawback of this solution is that you cannot force that a user has a primary identity (because the column needs to be nullable).
Another option would be to change to a DBMS that supports deferred constraints, then you can just insert the two rows and the constraint will only be checked at commit time. Or use a DBMS where you can have a partial index, then you could use the solution with an is_primary column
I would not implement it this way.
Remove the field primary_identity from table users, and the add an additional field to table user_profiles called is_primary, and use this rather as the indicator of a primary profile
This will prevent having NULLs for FKs, but still does not enforce for primary profile to exists -- that has to be managed by application.
Note the alternate key (unique index) {UserID, ProfileID} on Profile table and matching FK on PrimaryProfile.
The problem seems to be that you are trying to keep the primary identity information in the user_identities table.
Instead, I suggest you put the primary user info (name/email) into the users table. Do not foreign key to the user_identities table.
Only foreign key from the user_identities table
All constraints will now work ok as they are only one way.
user_identities cannot be entered unless the primary user (in table users) is present. Similarly the primary user should not be deletable where there are existing child identities (in user_identities).
You might want to change the name of the tables to "primary_users" and "secondary_users" to make it obvious what is going on.
Does that sound okay?
This question was raised at How to drop tables with cyclic foreign keys in MySQL from the delete side of things, but I think that one of the answers is applicable here as well:
SET foreign_key_checks = 0;
INSERT <user>
INSERT <user identity>
SET foreign_key_checks = 1;
Make that a transaction and commit it all at once. I haven't tried it, but it works for deletes, so I don't know why it wouldn't work for inserts.
I've not used it, but you could try INSERT IGNORE. I'd do the two of those, one for each table, such that once they are both done, referential integrity is maintaing. If you do them in a transaction, you can roll back if there is a problem inserting the second one.
Since you're ignoring constraints with this feature, you should do that check in program code instead, otherwise you may end up with data in your database that ignores your constraints.
Thanks to #Mihai for pointing out the problem with the above. Another approach would be to disable constraints whilst you do inserts, and re-enable them afterwards. However, on a large table that might produce more overhead than is acceptable - try it?
updateSchema runs well with an empty database, but the second time I get the following MySQL error:
SQLSTATE[HY000]: General error: 1025 Error on rename of
'./mydatabase/#sql-7f5_2b' to
'./mydatabase/mytable' (errno: 150)
According to a quick search this error happens on foreign constraint violations. The right approach would be for doctrine to disable foreign key checks when ALTERing a table.
Is there something I can do about this (besides patching Dcotrine)?
Further more I'm specifying:
'engine' => 'myisam',
... in the connectionOptions, but it gets ignored.
Edit:
When I remove foreign keys from other tables containing reference to mytable the error won't happen (it will happen with the next table which is still referenced by FKs but not with mytable).
Unfortunately, Doctrine doesn't handle this situation completely right.
You should disable the constraints by yourself and let Doctrine to recreate them.
To disable constraints, connect to MySQL and type:
SHOW CREATE TABLE mytable;
It will give you the SQL needed to create the table, where you'll see the constraint creation directive. Suppose the constraint is called 'mytable_fk', then you need to issue the command:
ALTER TABLE mytable
DROP CONSTRAINT mytable_fk;
The next time you run updateSchema, Doctrine will detect the missing restriction and will recreate it if needed.
I feel like I'm being stupid, but I can't find anywhere on the phpMyAdmin interface to add constraints to foreign keys e.g. CASCADE ON DELETE
I've looked for similar questions on here and on the phpMyAdmin wiki but I can't find anything about it.
I realise I could do this via the query interface, but I'd like to know how to do it through the graphical interface.
First, you should have your storage engine as InnoDB. Then select a table and go to 'Structure' tab.
Under the table you will see 'Relation view', click it. From there you could add constraints.
CASCADE
Whenever rows in the master (referenced) table are deleted (resp. updated), the respective rows of the child (referencing) table with a matching foreign key column will get deleted (resp. updated) as well. This is called a cascade delete (resp. update[2]).
RESTRICT
A value cannot be updated or deleted when a row exists in a foreign key table that references the value in the referenced table. Similarly, a row cannot be deleted as long as there is a reference to it from a foreign key table.
NO ACTION
NO ACTION and RESTRICT are very much alike. The main difference between NO ACTION and RESTRICT is that with NO ACTION the referential integrity check is done after trying to alter the table. RESTRICT does the check before trying to execute the UPDATE or DELETE statement. Both referential actions act the same if the referential integrity check fails: the UPDATE or DELETE statement will result in an error.
SET NULL
The foreign key values in the referencing row are set to NULL when the referenced row is updated or deleted. This is only possible if the respective columns in the referencing table are nullable. Due to the semantics of NULL, a referencing row with NULLs in the foreign key columns does not require a referenced row.
Firstly, you should choose storage engine as InnoDB.
Follow this way: click database_name -> More -> Designer
When I try to delete an object, I get a 'System.InvalidOperationException' with the following additional information:
The operation failed: The relationship could not be changed because
one or more of the foreign-key properties is non-nullable. When a
change is made to a relationship, the related foreign-key property is
set to a null value. If the foreign-key does not support null values,
a new relationship must be defined, the foreign-key property must be
assigned another non-null value, or the unrelated object must be
deleted.
How can I get more information? This message is like "something's wrong, but we are not going to reveal what"
The object/row you've tried to delete is probably a foreign key - the foreign key can't be null in the related table. Try deleting the other object/row first.
This issue would also happen if you tried to do this in SQL, you'd get:
The DELETE statement conflicted with the REFERENCE constraint 'FK_foo_bar'. The conflict occured in database...
I´m using linq to sql and I have a lot of tables with foreign keys leading to the UserId.
Is it possible to have some of these foreign tables cleaned upon deletion.
For example I want the users profile (other table) to be deleted automatically with the user but not the users forum posts.
Is this possible or do I have to handle this with code?
I think this link is very usefull.
LINQ to SQL does not support or
recognize cascade-delete operations.
If you want to delete a row in a table
that has constraints against it, you
must complete either of the following
tasks:
Set the ON DELETE CASCADE rule in the foreign-key constraint in the
database.
Use your own code to first delete the child objects that prevent the
parent object from being deleted.
I am not sure with code, but couldn't you set the Cascade on Delete option in SQL?