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:

 

     Client table                          Contact table

 

 

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.


Comments


Nicolas Martin said about 14 days later

Why don't you replace the 'main_contact_id' field by a 'Client_contact' table with many to many relationships ?

Jonathan Nieto said about 17 days later

The point when using this method is to know the main contact quickly, instead the contact table could have a "main" field which would indicate if the contact is the main of the client or not, but in this approach querying the main contact would be slower.



Hey Stranger, leave a comment:

ICE ANTARES