Symfony向MSSQL datetime字段插入数据的兼容方案问询
Symfony 向 MSSQL datetime 字段插入/更新数据解决方案
在使用Symfony操作MSSQL数据库时,遇到数据库字段为datetime类型,但Symfony Doctrine默认适配datetime2类型,且无法修改数据库结构的情况,需要实现数据的插入与更新。现有实体代码如下:
<?php /** * RendezVous * * @ORM\Table(name="RENDEZ_VOUS", indexes={@ORM\Index(name="IDX_292A17E650EAE44", columns={"id_utilisateur"})}) * @ORM\Entity */ class RendezVous { /** * @var \DateTime|null * * @ORM\Column(name="date_heure", type="datetime", nullable=true) */ private $dateHeure; /** * @var \Utilisateur * * @ORM\Id * @ORM\GeneratedValue(strategy="NONE") * @ORM\OneToOne(targetEntity="Utilisateur") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="id_utilisateur", referencedColumnName="id_utilisateur") * }) */ private $idUtilisateur; public function getDateHeure(): ?\DateTime { return $this->dateHeure; } public function setDateHeure(?\DateTime $dateHeure): self { $this->dateHeure = $dateHeure; return $this; } }
此前尝试的方法均失败:
- 直接创建
new DateTime()设置时间戳,存在兼容性问题; - 将DateTime对象格式化字符串后传入,实体要求必须是DateTimeInterface类型;
- 将实体字段声明为字符串类型,用格式化字符串插入,数据库要求传入datetime类型值。
可行解决方案
方法1:自定义Doctrine类型映射
创建自定义Doctrine类型,强制将Symfony的时间类型映射到MSSQL的datetime而非默认的datetime2。
- 创建自定义类型类
<?php namespace App\Doctrine\Type; use Doctrine\DBAL\Types\DateTimeType; use Doctrine\DBAL\Platforms\SQLServerPlatform; class SqlServerDateTimeType extends DateTimeType { public function getSQLDeclaration(array $column, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { // 针对MSSQL平台返回datetime类型 if ($platform instanceof SQLServerPlatform) { return 'datetime'; } return parent::getSQLDeclaration($column, $platform); } }
- 在
config/packages/doctrine.yaml中配置类型映射
doctrine: dbal: types: sqlserver_datetime: App\Doctrine\Type\SqlServerDateTimeType mapping_types: datetime: sqlserver_datetime
- 修改实体字段注解类型
/** * @var \DateTime|null * * @ORM\Column(name="date_heure", type="sqlserver_datetime", nullable=true) */ private $dateHeure;
方法2:事件监听自动修正时间范围
MSSQL的datetime类型仅支持1753-01-01到9999-12-31的时间区间,通过Doctrine事件监听,在数据持久化前自动修正时间范围。
- 创建事件监听器类
<?php namespace App\EventListener; use Doctrine\ORM\Event\PreFlushEventArgs; use App\Entity\RendezVous; class RendezVousDateTimeListener { public function preFlush(PreFlushEventArgs $args) { $em = $args->getEntityManager(); $uow = $em->getUnitOfWork(); // 处理待插入的实体 foreach ($uow->getScheduledEntityInsertions() as $entity) { $this->fixDateTimeRange($entity); } // 处理待更新的实体 foreach ($uow->getScheduledEntityUpdates() as $entity) { $this->fixDateTimeRange($entity); } } private function fixDateTimeRange($entity) { if (!$entity instanceof RendezVous) { return; } $dateHeure = $entity->getDateHeure(); if ($dateHeure instanceof \DateTime) { $minDate = new \DateTime('1753-01-01'); if ($dateHeure < $minDate) { $entity->setDateHeure($minDate); } } } }
- 在
config/services.yaml注册监听器
services: App\EventListener\RendezVousDateTimeListener: tags: - { name: doctrine.event_listener, event: preFlush }
方法3:直接使用DBAL原生SQL
绕过Doctrine ORM,直接用DBAL执行原生SQL,手动绑定参数并指定类型:
// 在控制器或服务中调用 $connection = $this->getDoctrine()->getConnection(); $dateHeure = new \DateTime(); $userId = 1; // 替换为实际用户ID $connection->executeQuery( 'UPDATE RENDEZ_VOUS SET date_heure = ? WHERE id_utilisateur = ?', [$dateHeure, $userId], [\PDO::PARAM_STR, \PDO::PARAM_INT] );
内容的提问来源于stack exchange,提问作者Piffre Nathanael
相关产品推荐
相关产品推荐

