You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。

  1. 创建自定义类型类
<?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);
    }
}
  1. 在config/packages/doctrine.yaml中配置类型映射
doctrine:
    dbal:
        types:
            sqlserver_datetime: App\Doctrine\Type\SqlServerDateTimeType
        mapping_types:
            datetime: sqlserver_datetime
  1. 修改实体字段注解类型
/**
 * @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事件监听,在数据持久化前自动修正时间范围。

  1. 创建事件监听器类
<?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);
            }
        }
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 11:02:41