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了。