由于tp进行数据查询,新增,修改,删除等都会进行(SHOW FULL COLUMNS FROM
)获取数据表字段及其数据类型对应关系
每次都进行查询有点浪费资源
提供两种解决方式
# 第一种
# tp config/database.php 中提供了开启数据库字段缓存
# 将 fields_cache 设置成true
fields_cache => true
# 查询过一次后,会生成缓存文件,只要缓存在就去查缓存
# 如果数据字段变更后,可以通过 php think optimize:schema 应用名 (多应用)
# php think optimize:schema (单应用)
# 更新字段缓存
php think optimize:schema admin
# 第二种
# 通过设置模型的schema属性
# 来告知数据库字段与类型对应关系
protected $schema = [
'username' => 'string',
'password' => 'string',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
$user = new User();
# where($field,$op,$condition)
# $field 字段
# $op 比较符 >,<,=....
# $condition 比较条件
#当使用等于条件$op可以省略
$user->where('id', 1);
# 等价与
$user->where('id', '=', 1);
#like语句
$user->where('username', 'like', '%username%');
# 多个条件可以通过链式操作
# 也可以给where 方法 传递数组代表多个where条件
# SELECT * FROM `user` WHERE ( `id` = '1' AND `username` LIKE '%username%' )
# 可以写成
$user->where([['id', '=', 1], ['username', 'like', '%username%']]);
# or 条件
# SELECT * FROM `user` WHERE ( `id` = '1' OR `username` LIKE '%username%' )
$user->where('id', 1)->whereOr('username', 'like', '%username%');
# where中传闭包可以将条件放到一个括号内(当成一个整体的where条件)
# SELECT * FROM `user` WHERE ( ( `id` = '1' AND `status` = '1' ) OR `username` LIKE '%username%' )
# 查找 id=1,status = 1 或者 username 中包含username的数据
$user->where(function ($query) {
$query->where('id', 1)->where('status', 1);
})->whereOr('username', 'like', '%username%');
# 如果不使用闭包
$user->where('id', 1)->where('status', 1)->whereOr('username', 'like', '%username%')
# 执行的是 SELECT * FROM `user` WHERE ( `id` = '1' AND `status` = '1' OR `username` LIKE '%username%' )
# 查找id=1,status =1 或者 id = 1,username 中包含username的数据
$user = new User();
# find 查找一条
$user->where('id', '>', 1)->find();
# select() 查找多条
$user->where('id', '>', 1)->select();
$user = new User();
# 通过field 限制要查询的字段
# 只查找id,username 字段
$user->where('id', '>', 1)->field(['id', 'username'])->find();
user(用户表),post(文章表)
假设用户和文章表一对一
在User模型中使用hasOne声明一个方法
# user模型中 声明post方法指明user和post表一对一关系
# 关联关系 user.id = post.user_id
public function post()
{
# 两者都属于一对一关系
# 只是强调概念不一样
# 强调user含有文章
return $this->hasOne(Post::class, 'user_id', 'id');
# 强调user属于某个文章
return $this->belongsTo(Post::class, 'id', 'user_id');
}
# 第一种方法获取关联数据
$user = new User();
$userInstance = $user->where('id', '>', 0)->find();
# 调用声明的关联函数来获取关联数据
$userInstance->post();
# 第2种方法通过with获取关联数据
$user = new User();
$userInstance = $user->where('id', '>', 0)->with('post')->select();
# 可以限制关联要查的字段,记得一定要查关联的字段
# 可以限制关联查询的条件
$userInstance = $user->where('id', '>', 0)->with(['post' => function ($query) {
# 限制查询post.id > 1的文章数据
# user_id 一定要查,否则 $userInstance[0]->post 是null(不查user_id则无法把post数据添加到user模型上去)
$query->where('id', '>', 1)->field(['title', 'user_id']);
}])->select();
#输出第一个用户的文章的标题
$userInstance[0]->post->title;
模型的一对一关联使用的不是join查询
数据是分开查询的
以user和post为例
先查user满足条件的数据,取出关联字段得到user_id 数组 user_ids
再查post.user_id in (user_ids) 中的数据
那么怎么查有文章的用户呢
$user = new User();
# 通过hasWhere过滤查找有文章的用户且用户id > 1
# id > 1 是user上的条件,需要带上表名 不能直接写id(post中也有id,分不清是谁的id)
$user->where('user.id', '>', 1)->hasWhere('post')->select();
我想查找一篇文章是那个用户写的呢
$user = new User();
# hasWhere第二个参数可以限制查询条件
# 查找用户,用户id > 1,用户需要有文章且文章的title叫做将进酒
$user->where('user.id', '>', 1)->hasWhere('post', function ($query) {
$query->where('title', '将进酒');
})->find();
hasWhere局限性
体现在不能像laravel的model模型一样进行嵌套过滤
假设user和post文章表一对一(user.id = post.user_id)
post属于某一个文章类型post_type(post.type_id = post_type.id)
如果我要查一个用户,该用户需要满足有文章且文章类型属于诗歌
用tp的模型的hasWhere无法得到该结果
$user = new User();
# hasWhere不支持嵌套
# 如果像laravel的话,应该可以这么写
# 可惜不行
$user->where('id', '>', 1)->hasWhere('post', function ($query) {
$query->hasWhere('type', function ($query) {
$query->where('name', '诗歌');
});
})->find();
通过关联新增,修改,删除
# 新增 user, post
$user = User::create(['username' => 'test_01', 'password' => '123456']);
# post 是user中定义的关联方法
$user->post()->save(['title' => '将进酒', 'type_id' => 1]);
# 等价于
# Post::create(['user_id'=>$user->id,'title' => '将进酒', 'type_id' => 1]);
# 通过关联修改post
$user = User::find(7);
# 新增是post()->save(),修改是post->save()
$user->post->save(['title' => '新将进酒']);
# 通过关联删除post
$user = User::find(7);
$user->post->delete();
User model 中定义
public function post()
{
# 两种声明方式
# 1.使用hasMany声明一个用户有多个文章
return $this->hasMany(Post::class, 'user_id', 'id');
# 2.使用belongsToMany声明一个用户属于多个文章
return $this->belongsToMany(Post::class, 'id', 'user_id');
}
# 用法和一对一的一样
# 通过with查询关联数据
$user = User::where('id', '=', 7)->with('post')->find();
$posts = $user->post;
# 通过声明的关联函数获取关联数据
$user = User::where('id', 7)->find();
$posts = $user->post();
# 由于使用的是一对多关联
# $user->post | $user->post() 返回的是多条 所以使用foreach遍历
# 一对一关联直接 $user->post->title | $user->post()->title 即可
foreach ($posts as $post) {
echo $post->title;
}
查询有文章的用户
$model = new User();
$user = $model->hasWhere('post')->select();
查询文章数大于等于两篇的用户
$model = new User();
$user = $model->has('post', '>=', 2)->select();
查找文章大于两篇的(要求文章type_id = 1,type_id = 1 意思是诗歌类型)
查找用户,要求用户发表过两篇及以上的诗歌文章
# 这时候使用model模型就有点无力了
# tp 的model 没有laravel的强大
# 改用DB类实现
# SELECT `user`.* FROM `user` LEFT JOIN `post` ON `user`.`id`=`post`.`user_id` WHERE `post`.`type_id` = '1' GROUP BY `user`.`id` HAVING count(post.id) >= 2
$user = Db::name('user')
->leftJoin('post', 'user.id = post.user_id')
->field(['user.*'])
->where('post.type_id', 1)
->group('user.id')
->having("count(post.id) >= 2")
->select();