From b90f94fe9a087b670462cd166165e101e226c470 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 14 Mar 2012 22:53:01 -0400 Subject: [PATCH] finished eager loading. --- framework/db/ar/ActiveFinder.php | 46 ++++++++++++++++++++++++- framework/db/dao/QueryBuilder.php | 7 ++-- framework/db/dao/TableSchema.php | 4 +-- tests/unit/framework/db/ar/ActiveRecordTest.php | 3 ++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/framework/db/ar/ActiveFinder.php b/framework/db/ar/ActiveFinder.php index 050d5d6..13f92c9 100644 --- a/framework/db/ar/ActiveFinder.php +++ b/framework/db/ar/ActiveFinder.php @@ -120,6 +120,11 @@ class ActiveFinder extends \yii\base\Object $q = new Query; $this->buildJoinQuery($joinTree, $q); + + if ($this->_hasMany && ($query->limit > 0 || $query->offset > 0)) { + $this->limitQuery($query, $q); + } + $rows = $q->createCommand($this->connection)->queryAll(); foreach ($rows as $row) { $joinTree->createRecord($row); @@ -202,7 +207,7 @@ class ActiveFinder extends \yii\base\Object } elseif (is_array($relation->via)) { // join via a pivoting table $r = new ActiveRelation; - $r->name = 'pt' . $this->_joinCount; + $r->name = 'vt' . $this->_joinCount; $r->hasMany = $relation->hasMany; foreach ($relation->via as $name => $value) { @@ -288,6 +293,8 @@ class ActiveFinder extends \yii\base\Object $quotedPrefixes = array( '@.' => $this->connection->quoteTableName($element->query->tableAlias, true) . '.', ); + $query->limit = $element->query->limit; + $query->offset = $element->query->offset; } $qb = $this->connection->getQueryBuilder(); @@ -436,4 +443,41 @@ class ActiveFinder extends \yii\base\Object return $columns; } + + protected function limitQuery($activeQuery, $query) + { + $q = clone $query; + $modelClass = $activeQuery->modelClass; + $table = $modelClass::getMetaData()->table; + $q->select = array(); + foreach ($table->primaryKey as $name) { + $q->select[] = $alias = $activeQuery->tableAlias . '.' . $name; + } + $q->distinct = true; + $rows = $q->createCommand($this->connection)->queryAll(); + if (count($table->primaryKey) === 1) { + $name = $table->primaryKey[0]; + $values = array(); + foreach ($rows as $row) { + $values[] = $table->columns[$name]->typecast($row[$name]); + } + $query->andWhere(array('in', $activeQuery->tableAlias . '.' . $name, $values)); + } else { + $ors = array('or'); + $prefix = $this->connection->quoteTableName($activeQuery->tableAlias, true) . '.'; + foreach ($rows as $row) { + $ands = array(); + foreach ($table->primaryKey as $name) { + $value = $table->columns[$name]->typecast($row[$name]); + if (is_string($value)) { + $value = $this->connection->quoteValue($value); + } + $ands[] = $prefix . $this->connection->quoteColumnName($name, true) . '=' . $value; + } + $ors[] = implode(' AND ', $ands); + } + $query->andWhere($ors); + } + $query->limit = $query->offset = null; + } } \ No newline at end of file diff --git a/framework/db/dao/QueryBuilder.php b/framework/db/dao/QueryBuilder.php index 986e0de..ee0298d 100644 --- a/framework/db/dao/QueryBuilder.php +++ b/framework/db/dao/QueryBuilder.php @@ -533,6 +533,7 @@ class QueryBuilder extends \yii\base\Object } } if ($parts !== array()) { + $operator = strtoupper($operator); return '(' . implode(") $operator (", $parts) . ')'; } else { return ''; @@ -580,6 +581,7 @@ class QueryBuilder extends \yii\base\Object $column = $this->quoteColumnName($column); } + $operator = strtoupper($operator); return "$column $operator (" . implode(', ', $values) . ')'; } @@ -600,9 +602,9 @@ class QueryBuilder extends \yii\base\Object } if ($operator === 'like' || $operator === 'not like') { - $andor = ' and '; + $andor = ' AND '; } else { - $andor = ' or '; + $andor = ' OR '; $operator = $operator === 'or like' ? 'like' : 'not like'; } @@ -610,6 +612,7 @@ class QueryBuilder extends \yii\base\Object $column = $this->quoteColumnName($column); } + $operator = strtoupper($operator); $parts = array(); foreach ($values as $value) { $parts[] = "$column $operator " . $this->connection->quoteValue($value); diff --git a/framework/db/dao/TableSchema.php b/framework/db/dao/TableSchema.php index 6e04fe0..9d8d09d 100644 --- a/framework/db/dao/TableSchema.php +++ b/framework/db/dao/TableSchema.php @@ -41,7 +41,7 @@ class TableSchema extends \yii\base\Object */ public $quotedName; /** - * @var array primary keys of this table. + * @var string[] primary keys of this table. */ public $primaryKey = array(); /** @@ -61,7 +61,7 @@ class TableSchema extends \yii\base\Object */ public $foreignKeys = array(); /** - * @var array column metadata of this table. Each array element is a [[ColumnSchema]] object, indexed by column names. + * @var ColumnSchema[] column metadata of this table. Each array element is a [[ColumnSchema]] object, indexed by column names. */ public $columns = array(); diff --git a/tests/unit/framework/db/ar/ActiveRecordTest.php b/tests/unit/framework/db/ar/ActiveRecordTest.php index 88ab27e..7051db7 100644 --- a/tests/unit/framework/db/ar/ActiveRecordTest.php +++ b/tests/unit/framework/db/ar/ActiveRecordTest.php @@ -250,6 +250,9 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase $this->assertEquals(1, $orders[0]->books[0]->id); $this->assertEquals(2, $orders[0]->books[1]->id); $this->assertEquals(2, $orders[1]->books[0]->id); + + $orders = Order::find()->with('items')->order('@.id')->limit(2)->all(); + $this->assertEquals(2, count($orders)); } /*