Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mysql circular dependency in foreign key constraints

Given the schema:

enter image description here

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)?

like image 718
Flavius Avatar asked Sep 29 '12 11:09

Flavius


People also ask

How do you fix a circular dependency problem?

There are a couple of options to get rid of circular dependencies. For a longer chain, A -> B -> C -> D -> A , if one of the references is removed (for instance, the D -> A reference), the cyclic reference pattern is broken, as well. For simpler patterns, such as A -> B -> A , refactoring may be necessary.

How do you avoid circular dependencies?

To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.

Are foreign keys bidirectional?

Target foreign keys normally occur in bidirectional one-to-one mappings, because one side has a foreign key and the other shares the same foreign key in the other's table.

What causes circular dependency?

A circular dependency occurs when two classes depend on each other. For example, class A needs class B, and class B also needs class A. Circular dependencies can arise in Nest between modules and between providers. While circular dependencies should be avoided where possible, you can't always do so.


1 Answers

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

like image 153
a_horse_with_no_name Avatar answered Oct 05 '22 12:10

a_horse_with_no_name