Circular table relations in a symfony project
Symfony | Technical | Development | July 26, 2010
Circular relations in the database is the fact to have a foreign key of one table in another and at the same time have another foreign key of that table in the first one. Usually this kind of relations are undesired because they bring problems while making queries or inserting data. However sometimes they are utilized to improve performance. For example we could have a model like:
There is a client which have a collection of contacts, but there is also a main contact. This record is wanted to be retrieved very fast, in other words without a query.
When working with symfony 1.* and doctrine there could be a shema like:
Client:
tableName: client
actAs:
Timestampable:
columns:
id: { type: integer , length: 20 , primary: true , autoincrement: true }
main_contact_id: { type: integer , length: 20 }
code: { type: string , length: 10 , notnull: true }
Contact:
tableName: contact
columns:
id: { type: integer , length: 20 , primary: true , autoincrement: true }
client_id: { type: integer , length: 20 , notnull: true }
name: { type: string , length: 200 , notnull: true }
position: { type: string , length: 100 }
Until now everything is all right, however a problem arises when trying to load data using the fixtures functionality. The problem is the ORM does not know which record to insert first. This problem can be fix adding the following code in the Client.class.php file:
public function save(Doctrine_Connection $conn = null) { if (!sfContext::hasInstance()) { $mainContact = $this->getMainContact(); $this->setMainContact(null); $this->addContact($mainContact); parent::save($conn); $this->setMainContact($mainContact); } parent::save($conn); }
The code let the client to be saved without a main contact. Then once saved both, the client and the contact, sets the main contact.
Now some data can be upload without hassle:
Client:
Client_1:
MainContact: Contact_1
code : '00001001'
Contact:
Contact_1:
Client: Client_1
name: 'Jonathan Nieto'
position: 'Developer'
This way circular data can be upload in a symfony project.
Circular relations there always be a problem but because of performance sometimes they are needed.
Why don't you replace the 'main_contact_id' field by a 'Client_contact' table with many to many relationships ?