BUG:Model类的select方法默认只返回1条记录php
TP的手册中写的是select方法返回的是所有的记录,但我在实际操做中,返回的只有1条记录,咱们再次进行源码的分析。sql
(1)Action中的代码以下:thinkphp
- $operaInfo = new Model("tbloperainfo");
- $list = $operaInfo->select();
(2)根据代码咱们进入Model类的select方法,在select方法中又调用了Db类的select方法:数组
- $resultSet = $this->db->select($options);
(3)select方法中有以下的代码片断,对查询的sql进行了处理:ide
- $sql = str_replace(
- array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'),
- array(
- $this->parseTable($options['table']),
- $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
- $this->parseField(isset($options['field'])?$options['field']:'*'),
- $this->parseJoin(isset($options['join'])?$options['join']:''),
- $this->parseWhere(isset($options['where'])?$options['where']:''),
- $this->parseGroup(isset($options['group'])?$options['group']:''),
- $this->parseHaving(isset($options['having'])?$options['having']:''),
- $this->parseOrder(isset($options['order'])?$options['order']:''),
- $this->parseLimit(isset($options['limit'])?$options['limit']:'')
- ),$this->selectSql);
- $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
- return $this->query($sql);
在处理的时候调用了parseLimit方法,因为面向对象的多态性,这个方法应该是在DbMssql中的parseLimit方法。咱们看下该方法的参数:isset($options['limit'])?$options['limit']:'' 这个表达式结果应该为空字符串'',由于咱们在调用Model类的select方法的时候没有传任何参数。this
咱们进入DbMssql看下代码以下:spa
- public function parseLimit($limit) {
- if(empty($limit)) $limit=1;
- $limit = explode(',',$limit);
- if(count($limit)>1)
- $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
- else
- $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
- return $limitStr;
- }
(4)在parseLimit方法中,第一步将$limit赋值为1;第二部将$limit拆分为数组;第三部判断数组的元素个数后执行了以下的代码:对象
$limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; 字符串
在这里咱们能够看出$limitStr的具体值为:'(T1.ROW_NUMBER BETWEEN 1 AND 1)'get
好,咱们继续跟踪源码。
(5)第3步对$selectSql处理后,调用了DbMssql类的query方法,在该方法中又调用了getAll方法将查询的结果存入$result数组,紧接着将$result一层层返回。
(6)好,到此为止执行流程已经所有结束。咱们看下具体执行的SQL,以下:
- SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE (T1.ROW_NUMBER BETWEEN 1 AND 1)
看下执行的SQL,发现引发这个BUG的缘由就是: (T1.ROW_NUMBER BETWEEN 1 AND 1) 这个SQL片断。
(7)缘由找到了,该如何处理呢?
咱们确定是在DbMssql类的parseLimit方法下手,由于咱们须要查询全部的记录,所以该方法返回的值最好是为 '' 。咱们将parseLimit方法的第一行代码修改成以下的代码:
- if(emptyempty($limit)) {
- return $limit;
- }
就是若是$limit为空,直接返回。修改后刷新下页面发现报错了,看了执行的SQL以下:
- SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE
发现SQL到WHERE关键字就没了,咱们看下DbMssql中$selectSql的定义:
- protected $selectSql = 'SELECT T1.* FROM (SELECT ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER, thinkphp.* FROM (SELECT %DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 WHERE %LIMIT%'
再结合parseLimit方法中的代码,具体处理方法以下:
1.将SQL中的WHERE删掉
2.在parseLimit中将代码修改以下:
- if(count($limit)>1)
- $limitStr = ' WHERE (T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
- else
- $limitStr = ' WHERE (T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
便是将WHERE直接放到$limitStr中,这样就OK了。