如何在Yii2框架中使用MSSQL的datetimeoffset列类型
Yii2 + MSSQL 支持datetimeoffset类型的解决方案
一、快速解决迁移创建datetimeoffset列的问题
你当前用$this->dateTime()会生成datetime2类型,是因为Yii2的MSSQL Schema默认没有datetimeoffset的快捷方法,直接用以下两种方式即可创建datetimeoffset列:
方法1:直接指定原生列类型
$this->createTable('{{%table_with_datetimeoffset}}', [ 'dtm' => 'datetimeoffset NULL', ]);
方法2:用SchemaBuilder构建(更符合Yii2规范)
$this->createTable('{{%table_with_datetimeoffset}}', [ 'dtm' => $this->getDb()->getSchema()->createColumnSchemaBuilder('datetimeoffset')->null(), ]);
二、遵循Yii2规范扩展ORM,映射datetimeoffset到\DateTime类
要让Yii2的ORM正确处理datetimeoffset类型的读写转换,需要自定义Schema和ColumnSchema组件:
1. 自定义ColumnSchema处理类型转换
创建app\db\mssql\ColumnSchema.php:
namespace app\db\mssql; use yii\db\mssql\ColumnSchema as BaseColumnSchema; class ColumnSchema extends BaseColumnSchema { public function init() { parent::init(); if ($this->type === 'datetimeoffset') { $this->phpType = 'datetime'; } } public function typecast($value) { if ($value === null) { return null; } if ($this->type === 'datetimeoffset') { if (is_string($value)) { // 解析MSSQL返回的datetimeoffset格式字符串为DateTime对象 return \DateTime::createFromFormat('Y-m-d H:i:s.u P', $value) ?: new \DateTime($value); } elseif (is_integer($value)) { return (new \DateTime())->setTimestamp($value); } } return parent::typecast($value); } }
2. 自定义Schema使用新的ColumnSchema
创建app\db\mssql\Schema.php:
namespace app\db\mssql; use yii\db\mssql\Schema as BaseSchema; class Schema extends BaseSchema { protected function createColumnSchema() { return new ColumnSchema(); } }
3. 配置数据库组件启用自定义Schema
在数据库配置文件(如config/db.php)中修改db组件:
return [ 'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'sqlsrv:Server=localhost;Database=your_database', 'username' => 'your_username', 'password' => 'your_password', 'charset' => 'utf8', 'schemaMap' => [ 'sqlsrv' => 'app\db\mssql\Schema', 'mssql' => 'app\db\mssql\Schema', ], ], ], ];
4. 可选:为Migration添加datetimeoffset快捷方法
创建自定义Migration基类app\db\Migration.php:
namespace app\db; use yii\db\Migration as BaseMigration; class Migration extends BaseMigration { public function dateTimeOffset($precision = null) { return $this->getDb()->getSchema()->createColumnSchemaBuilder('datetimeoffset', $precision); } }
之后迁移文件继承这个基类,就可以像用dateTime()一样调用:
$this->createTable('{{%table_with_datetimeoffset}}', [ 'dtm' => $this->dateTimeOffset()->null(), ]);
内容的提问来源于stack exchange,提问作者SWilk
相关产品推荐
相关产品推荐

