数据库表模型
介绍
传统关系型数据库(MySQL)的模型,日常增删改查完全够用,支持复合主键、联合主键。
模型定义
喜闻乐见的对命名空间、类名无要求,只要按照规定写注解即可!
@Entity
注解为定义实体类
@Table
注解为定义数据表
@Column
注解为定义字段
@DDL
定义表结构的 SQL 语句
具体定义看下面代码:
namespace Test;
use Imi\Model\Model;
use Imi\Model\Annotation\Table;
use Imi\Model\Annotation\Column;
use Imi\Model\Annotation\Entity;
/**
* 定义为实体
* @Entity
* 指定实体为test,复合主键id和a
* @Table(name="test", id={"id", "a"})
*/
class Test extends Model
{
/**
* ID
* 字段id,类型int,长度10,是主键,第0个主键,是自增字段
* @Column(name="id", type="int", length=10, isPrimaryKey=true, primaryKeyIndex=0, isAutoIncrement=true)
* @var int
*/
protected $id;
/**
* aaa
* @Column(name="a", type="string", length=255, isPrimaryKey=true, primaryKeyIndex=1)
* @var string
*/
protected $a;
/**
* bbb
* @Column(name="b", type="string", length=255)
* @var string
*/
protected $b;
/**
* ccc
* @Column(name="c", type="string", length=255)
* @var string
*/
protected $c;
/**
* Get iD
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set iD
*
* @param int $id ID
*
* @return self
*/
public function setId(int $id)
{
$this->id = $id;
return $this;
}
/**
* Get aaa
*
* @return string
*/
public function getA()
{
return $this->a;
}
/**
* Set aaa
*
* @param string $a aaa
*
* @return self
*/
public function setA(string $a)
{
$this->a = $a;
return $this;
}
/**
* Get bbb
*
* @return string
*/
public function getB()
{
return $this->b;
}
/**
* Set bbb
*
* @param string $b bbb
*
* @return self
*/
public function setB(string $b)
{
$this->b = $b;
return $this;
}
/**
* Get ccc
*
* @return string
*/
public function getC()
{
return $this->c;
}
/**
* Set ccc
*
* @param string $c ccc
*
* @return self
*/
public function setC(string $c)
{
$this->c = $c;
return $this;
}
}
需要使用注解将表、字段属性全部标注。并且写上get
和set
方法,可以使用模型生成工具生成。
模型中可以加入虚拟字段,通过注解@Column(virtual=true)
,虚拟字段不参与数据库操作。
模型注解
@Entity
写在类上,定义类为实体模型类
用法:
@Entity
序列化时不使用驼峰命名,使用原本的字段名:
@Entity(false)
@Table
写在类上,定义数据表
用法:
@Table('tb_user')
指定数据库连接池:
@Table(name='tb_user', dbPoolName='指定数据库连接池名')
指定主键:
@Table(name='tb_user', id='id')
指定多个主键
@Table(name='tb_user', id={'id1', 'id2'})
@DDL
写在类上,定义表结构
用法:
/**
* ArticleBase
* @Entity
* @Table(name="tb_article", id={"id"})
* @DDL("CREATE TABLE `tb_article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`content` mediumtext NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT")
* @property int $id
* @property string $title
* @property string $content
* @property string $time
*/
abstract class ArticleBase extends Model
{
}
@JsonEncode
写在类上,设定 JSON 序列化时的配置
不使用 Unicode 编码转换中文:@JsonEncode(JSON_UNESCAPED_UNICODE)
完整参数:@JsonEncode(flags=0, depth=512)
@Column
写在属性上,定义字段列
@Column(name="字段名", type="字段类型", length="长度", nullable="是否允许为空true/false", accuracy="精度,小数位后几位", default="默认值", isPrimaryKey="是否为主键true/false", primaryKeyIndex="联合主键中的第几个,从0开始", isAutoIncrement="是否为自增字段true/false", virtual="虚拟字段,不参与数据库操作true/false", updateTime=true)
当你指定
type=json
时,写入数据库时自动json_encode
,从数据实例化到对象时自动json_decode
当你指定
type=list
并且设置了listSeparator
分割符时,写入数据库时自动implode
,从数据实例化到对象时自动explode
updateTime
:save/update 模型时是否将当前时间写入该字段。支持 date/time/datetime/timestamp/year/int/bigint。当字段为 int 类型,写入秒级时间戳。当字段为 bigint 类型,写入毫秒级时间戳。
@JsonNotNull
写在属性上,无参数。
当字段值不为 null 时才序列化到 json
@Serializable
写在属性上,序列化注解
用法:
禁止参与序列化(toArray()
或json_encode()
不包含该字段):
@Serializable(false)
@Serializables
写在类上,批量设置序列化注解,优先级低于针对属性单独设置的@Serializable
注解
用法:
白名单(序列化后只显示id、name字段):
@Serializables(mode="allow", fields={"id", "name"})
黑名单(序列化后,排除id、name字段)
@Serializables(mode="deny", fields={"id", "name"})
@ExtractProperty
写在属性上,提取字段中的属性到当前模型
用法:
提取该属性中的userId
值到当前模型中的userId
:
@ExtractProperty("userId")
提取该属性中的userId
值到当前模型中的userId2
:
@ExtractProperty(fieldName="userId", alias="userId2")
支持多级提取到当前模型中的userId2
:
/**
* @ExtractProperty(fieldName="ex.userId", alias="userId2")
*/
protected $xxx = [
'ex' => [
'userId' => 123,
],
];
模型操作
初始化模型
$testModel = TestModel::newInstance([
'a' => 'abc',
'b' => 'def',
]);
第二种方法:
$testModel = TestModel::newInstance();
$testModel->set([
'a' => 'abc',
'b' => 'def',
]);
查询构建器
imi 中数据库查询连贯操作都来自于查询器,查询器的创建方式:
查询结果返回模型对象:
$query = TestModel::query();
查询结果返回数组:
$query = TestModel::dbQuery();
如果希望使用
field()
去指定返回字段,请使用dbQuery()
查询记录
查询记录并返回一个模型实例。
// where id = 1
$testModel = TestModel::find(1);
// 复合主键 where a = 1 and b = 'abc'
$testModel = TestModel::find(1, 'abc');
echo $testModel->getId();
// 指定多个字段条件 where a = 1 and b = 'abc'
$testModel = TestModel::find([
'a' => 1,
'b' => 'abc',
]);
批量查询记录
// 查询所有记录
$list = TestModel::select();
// 带 where 条件的查询,id = 1
$list = TestModel::select([
'id' => 1
]);
// where 回调条件
$list = TestModel::select(function(IQuery $query){
$query->where('id', '=', 1);
});
// 查询器查询
$list = TestModel::query()->where('id', '=', 1)->select()->getArray();
// 以上所有 $list 都是 TestModel[] 类型
分页查询带扩展字段
查询总记录数、总页数:
$page = 1;
$count = 10;
$data = TestModel::query()->paginate($page, $count);
$data->getList(); // 列表数据
$data->getTotal(); // 总记录数
$data->getLimit(); // $count === 10
$data->getPageCount(); // 总页数
var_dump($data->toArray()); // 转数组
var_dump(json_encode($data)); // 支持序列化
// 数据格式如下:
[
'list' => [],
'total' => 100,
'limit' => 10,
'page_count' => 10,
]
不查询总记录数、总页数:
$page = 1;
$count = 10;
$data = TestModel::query()->paginate($page, $count, [
'total' => false,
]);
var_dump($data->toArray()); // 转数组
var_dump(json_encode($data)); // 支持序列化
// 数据格式如下:
[
'list' => [],
'limit' => 10,
]
聚合函数
TestModel::count();
TestModel::sum('id');
插入
$testModel = TestModel::newInstance();
$testModel->setA('1');
$testModel->setB('1');
$testModel->setC('1');
$result = $testModel->insert();
// $result 用法同数据库中的 insert() 返回值用法
echo '插入的自增ID:', $testModel->getId();
更新
$testModel = TestModel::find(1, 'abc');
$result = $testModel->update();
// $result 用法同数据库中的 update() 返回值用法
批量更新
// update tb_test set a = 'abc' where id > 5
TestModel::updateBatch([
'a' => 'abc',
], 'id > 5');
保存
// 自动判断是插入还是更新
$testModel->save();
删除
$testModel = TestModel::find(1, 'abc');
$result = $testModel->delete();
// $result 用法同数据库中的 delete() 返回值用法
批量删除
// delete tb_test set a = 'abc' where id > 5
TestModel::deleteBatch([
'a' => 'abc',
], 'id > 5');
查询器
$testModel = TestModel::query()->where()->join()->select()->get();
// $testModel 依然是 TestModel 类型
对象转数组
将当前对象作为数组返回:
属性的值,如果是对象,那依然会保持原样。只保证第一层是数组。
$testModel = TestModel::find(1, 'abc');
$array = $testModel->toArray();
将当前模型转为数组:
包括属性的值也会被转为数组
$testModel = TestModel::find(1, 'abc');
$array = $testModel->convertToArray(); // 过滤注解定义的隐藏属性
$array = $testModel->convertToArray(false); // 不过滤
转换模型数组为模型
$list = TestModel::select();
$arrayList = TestModel::convertListToArray($list); // 过滤注解定义的隐藏属性
$arrayList = TestModel::convertListToArray($list, false); // 不过滤