yii框架中模型链式查询需先调用find()获取activequery实例,再链式配置where、orderby等条件,all()等终结方法才执行sql;条件组合用andwhere避免覆盖,关联查询用with或joinwith,分页需分离count与limit/offset。

在Yii框架中用模型做数据库查询时,想让代码既清晰又高效,避免嵌套多层where、orderBy再拼接条件,就得掌握链式调用的正确写法——它不是简单地连点调用,而是要理解每个方法返回值类型和执行时机。
基础链式查询:从find()开始
第一步必须调用模型类的find()静态方法,它返回一个ActiveQuery实例,后续所有链式方法都作用于这个对象上。不调find()就直接写User::where(...)会报错,因为where()不是模型类的静态方法。
调用find()后可立即接where()→orderBy()→limit(),例如:User::find()->where(['status' => 1])->orderBy('created_at DESC')->limit(10)->all()。
注意:all()、one()、count()这类终结方法才会真正触发SQL执行,前面所有链式调用只是配置查询对象,不查库。
条件组合:用andWhere/orWhere避免覆盖
方法一:连续调用andWhere()追加条件
User::find()->where(['type' => 'admin'])->andWhere(['status' => 1])->andWhere(['>=', 'last_login', '2024-01-01'])->all()——每条andWhere()都会用AND连接,生成WHERE type = 'admin' AND status = 1 AND last_login >= '2024-01-01'。
方法二:传入复合数组一次写完
User::find()->where(['and', ['type' => 'admin'], ['status' => 1], ['>=', 'last_login', '2024-01-01']])->all()——效果等同方法一,但可读性稍差,适合条件逻辑复杂时手动控制AND/OR层级。
【不要用多个where()】:第二次调用where()会完全覆盖第一次的条件,不是追加。
关联查询链式写法
第一步:在模型里定义好关联关系(如User模型中声明getProfile()返回hasOne(Profile::class, ['user_id' => 'id']))
第二步:调用with()预加载关联数据,支持链式继续加条件
User::find()->with('profile')->where(['user.status' => 1])->andWhere(['profile.is_verified' => 1])->all()——这里with('profile')必须放在where()前或后均可,但关联表字段过滤要用表别名(默认是关联名小写),否则会找不到字段。
第三步:若需对关联表做JOIN而非LEFT JOIN,改用joinWith()
User::find()->joinWith('profile')->where(['profile.is_verified' => 1])->all()——这会生成INNER JOIN,未关联记录将被自动过滤掉。
分页与数据处理链式衔接
① 先调pagination配置总条数和当前页
$query = User::find()->where(['status' => 1]);
② 创建分页对象并绑定查询
$pagination = new Pagination(['totalCount' => $query->count(), 'pageSize' => 20]);
③ 链式追加limit和offset
$users = $query->offset($pagination->offset)->limit($pagination->limit)->all();
这三步不能合并成一行,因为count()需要单独执行一次统计SQL,而offset/limit影响的是主查询——混在一起会导致count结果不准。











