开发者

Doctrine nest multiple joins

I am trying to optimize a symfony application with Doctrine. I've stumbled upon the following problem:

In the view I used $project->getProgress(); but by doing this the number of queries increase as there are more projects. So I tried to put the progress into the projects query(overriding the findAll method) with a left join, but this didn't work out. The number of queries actually increased.

public function findAll($hydrationMode = null)
{
    $q = $this->createQuery('p')
                    ->leftJoin('p.progress pr')
                    ->leftJoin('pr.sfGuardUser u')
                    ->leftJoin('p.raws r')
                    ->leftJoin('p.series');
    return $q->execute(array(), $hydrationMode);
}

This is the result I'm trying to create with the least possible amount of queries:

array() {
  [0]=>
  array() {
    ["id"]=> string(1) "1"
    ...
    ["progress"]=>
    array() {
        array() {
            array() { progress1 }
            array() { progress2 }
            array() { progress3 }
            ....
        }
    }
  }

I've looked through the documentation of both symfony and Doctrine and couldn't find my answer. I've also searched on google for quite a while. (I've been looking for a solution for over a few months now) I hope I've described my problem good enough.

schema.yml:

projects:
  actAs:
    Timestampable: ~
  columns:
    user_id: integer(4)
    series_id: bigint
    pages: int
    chapter: string
    translators_id: bigint
    proofreaders_id: bigint
    cleaners_id: bigint
    typesetters_id: bigint
    raws_id: bigint
    hide_project: bool
    complete: bool
  relations:
    sfGuardUser:
      local: user_id
      foreign: id
      onDelete: CASCADE
    series:
      local: series_id
      foreign: id
   开发者_StackOverflow中文版   type: one
      foreignType: many
      onDelete: CASCADE
    progress:
      local: id
      foreign: projects_id
      onDelete: CASCADE
      type: one
      foreignType: many

projectsProgress:
  actAs: [Timestampable]
  columns:
    projects_id: bigint
    user_id: integer(4)
    job:
      type: enum
      notnull: true
      values: [tl,pr,cl,ts]
    beginpage: int
    endpage: int
    complete: bool
    file: string
    url: clob
  relations:
    sfGuardUser:
      local: user_id
      foreign: id
      onDelete: CASCADE
    projects:
      local: projects_id
      foreign: id
      onDelete: CASCADE
      foreignAlias: progress


The problem of using hydrate mode is that you could fetch data that wont use. I don't really know how doctrine fetch all data but assume that for each project brings all required data adding, at least, one more query...

For complex query's (and optimization) i prefer doing a manual query and manage to bring all needed data in one query, for example:

$query = "SELECT ... FROM projects p LEFT JOIN progress pr (LEFT JOIN sfGuardUser u (LEFT JOIN...) ON pr.user_id = u.id ) ON p.id = pr.projects_id"

$rs = Doctrine_Manager::getInstance()->getCurrentConnection()->fetchAssoc($query);

being $rs an array with selected data. Having all data you can make an array as you like, but remember that this way you do one query (reducing the db load) but add some time machine parsing the array.


You need to modify the query that fetches the Project object to include the joins. Conventionally, queries that fetch Project objects should be placed in ProjectTable.

If you want to modify all queries or subsets of queries of Project, look into Doctrine Query Execution Listeners.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜