首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

ThinkPHP 3.2 關聯查詢解決方案:RelationModel 與 ViewModel 實戰對比

     編輯:PHP 綜合知識

場景:三表關聯查詢

-- 用戶表
test_user: id, username, tel

-- 用戶頭像表(一對一)
test_avatar: uid, avatar

-- 產品表(一對多:一用戶多產品)
test_pro: id, uid, name

方案一:RelationModel(已棄用,不推薦新專案使用)

class ProModel extends RelationModel {
    protected $_link = [
        'Avatar' => [
            'mapping_type' => self::HAS_ONE,
            'class_name' => 'Avatar',
            'foreign_key' => 'uid',
            'mapping_fields' => 'avatar',
            'as_fields' => 'avatar',
        ],
        'User' => [
            'mapping_type' => self::BELONGS_TO,
            'class_name' => 'User',
            'foreign_key' => 'uid',
            'mapping_fields' => 'username,tel',
            'as_fields' => 'username:user_name,tel:user_tel',
        ],
    ];
}

// 使用
$pro = M('Pro')->relation(true)->find(1);
// 結果包含:id, uid, name, avatar, user_name, user_tel

常見坑點

  • HAS_ONE vs BELONGS_TO:外鍵在哪張表?在關聯表用 HAS_ONE,在主表用 BELONGS_TO
  • mapping_fields 必須指定,否則預設全欄位
  • as_fields 別名避免欄位衝突
  • ThinkPHP 3.2.3+ 建議改用 ViewModel

方案二:ViewModel(推薦,SQL 級關聯,效能更好)

class ProViewModel extends ViewModel {
    public $viewFields = [
        'test_pro' => ['id', 'uid', 'name', '_type' => 'LEFT'],
        'test_avatar' => ['avatar', '_on' => 'test_pro.uid=test_avatar.uid', '_type' => 'LEFT'],
        'test_user' => ['username', 'tel', '_on' => 'test_pro.uid=test_user.id', '_type' => 'LEFT'],
    ];
}

// 使用
$pro = M('ProViewModel')->find(1);
// 自動生成 SQL:
// SELECT tp.id, tp.uid, tp.name, ta.avatar, tu.username, tu.tel
// FROM test_pro tp
// LEFT JOIN test_avatar ta ON tp.uid = ta.uid
// LEFT JOIN test_user tu ON tp.uid = tu.id
// WHERE tp.id = 1

ViewModel 關鍵配置

方案三:原生 SQL / Query Builder(最靈活、效能最佳)

$result = Db::table('test_pro')
    ->alias('p')
    ->join('test_avatar a', 'p.uid = a.uid', 'LEFT')
    ->join('test_user u', 'p.uid = u.id', 'LEFT')
    ->field('p.id, p.uid, p.name, a.avatar, u.username, u.tel')
    ->find(1);

ThinkPHP 3.2 常見 SQL 問題與解決

問題:字段存儲逗號分隔 ID(如 {1,2,3,4,5}),如何查詢包含特定 ID 的記錄?

// 方案一:模糊查詢(效能差,不走索引)
$where['field'] = ['LIKE', "%{$id}%"];

// 方案二:FIND_IN_SET(MySQL 專用,可走索引)
$where['field'] = ['EXP', "FIND_IN_SET({$id}, field)"];

// 方案三:正則(最精確,效能中等)
$where['field'] = ['REGEXP', "[[:<:]]{$id}[[:>:]]"]; // 邊界匹配

遷移建議:ThinkPHP 3.2 → 5.1/6.0/8.0

屬性說明
_onJOIN 條件,支援多欄位 ['a.id=b.id', 'a.type=b.type']
_typeJOIN 類型:LEFT、RIGHT、INNER、FULL
_as表別名
欄位定義['id', 'name', 'title:new_title'] 支援別名
3.2 寫法5.1+ 寫法
M('Model')model('Model') 或 Db::name('table')
RelationModelmodel()->with('relation')
ViewModelDb::view() 或模型關聯 hasOne()/belongsTo()
$_link模型類別定義 public function avatar() { return $this->hasOne(Avatar::class, 'uid', 'uid'); }

最佳實務總結

  1. 新專案直接使用 ThinkPHP 6.0/8.0,原生支援 Eloquent 風格關聯
  2. 舊專案維護:ViewModel 優於 RelationModel,SQL 可見、可調優
  3. 複雜查詢直接寫 SQL 或 Query Builder,不要強行套用 ORM
  4. 關鍵查詢加上索引、EXPLAIN 分析、慢查詢日誌
  5. 關聯定義集中在模型類別,控制器保持精簡

掌握 ViewModel 與原生查詢構建器,能解決 95% 的關聯查詢需求,避開 RelationModel 的諸多坑點,為系統遷移鋪平道路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved