Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine and unrefreshed relationships

Tags:

php

doctrine

I am seeing an unexpected caching effect in Doctrine (1.2.4).

I have a couple of related tables defined by the following YAML (several additional fields not used in the example removed). Just a simple 1-Many relationship from students to schools.

School:
  tableName: tblschool
  columns:
    sch_id:
      name: sch_id as id
      primary: true
      autoincrement: true
      type: integer(4)
    sch_name:
      name: sch_name as name
      type: string(50)
Student:
  tableName: tblstudent
  columns:
    stu_id:
      name: stu_id as id
      primary: true
      autoincrement: true
      type: integer(4)
    stu_sch_id:
      name: stu_sch_id as school_id
      type: integer(4)
  relations:
    School:
      local: school_id
      foreign: id
      foreignAlias: Students

I can create a simple Doctrine (1.2.4) query to get back a student with

  $result1 = Doctrine_Query::create()
           ->from('Student s')
           ->where('s.id = 1')
           ->execute();

and then extract out the corresponding school name with

foreach ($result1 as $result) { $ans[] = $result->School["name"]; }

I now modify the school_id (that causes the relationship) by following this with:

foreach ($result1 as $result) 
   { $result["school_id"] = 1 - $result["school_id"]; $result->save(); }

(I have set up the DB so that this gives another valid school ID).

If I were to now, immediately, try to access the relationship I will get the old school's name. I understand this - it is because I've not called refreshRelated(). What I find unexpected is that if I immediately make another query duplicating the first

  $result2 = Doctrine_Query::create()
           ->from('Student s')
           ->where('s.id = 1')
           ->execute();

and get its result

foreach ($result2 as $result) { $ans[] = $result->School["name"]; }

when I examine the contents of my array I find that, in both cases, I have the same school name. In other words, even though I've done a second query and am looking at the result of the query the relationship is not refreshed.

The data in the database is fine and consistent; i.e. appropriate students and schools exist. E.g. running the above sequence a second time - in a different program execution - uses the other school name (although again duplicated).

Where is this caching coming from?

like image 561
borrible Avatar asked Jun 16 '11 15:06

borrible


1 Answers

Doctrine use a little caching on the relations : your Student->School is stored into a Student attribute, and your Student->school_id too, in another attribute.

When you change your Student->school_id, the database get queryied, and the Student->school_id change, but the Student->School doesn't, as rehydrating this object might be CPU/memory expansive.

Doctrine provide some method to refresh the relations, but it's the developper's responsability to use it.

Example :

$student->refreshRelated('School'); //refreshes only the School relation
$student->refreshRelated(); //refreshes every relation of the $student

But there's another caching. Doctrine keeps all the hydrated object in memory, in order to limit the request number. So when you query again for your student, you find that your Student->School hasn't changed.

like image 174
Clement Herreman Avatar answered Nov 05 '22 16:11

Clement Herreman