Laravel - 从字符串转换日期和/或时间时转换失败

Laravel - Conversion failed when converting date and/or time from character string

提问人:Rafael Oliveira 提问时间:10/31/2023 最后编辑:Karl HillRafael Oliveira 更新时间:10/31/2023 访问量:77

问:

我正在使用 Laravel 9 和 PHP 8.0。当我尝试更新用户时,出现以下异常:

SQLSTATE[22007]: [Microsoft][ODBC Driver 18 for SQL Server][SQL 服务器]转换日期和/或时间时转换失败 字符串。

我认为正在执行的查询是 Laravel 内部的:

SELECT
  count(*) AS aggregate
FROM
  [ users ]
WHERE
  [ email ] = user_email
  AND [ id ] <> user_id
  AND [ deleted_at ] = NULL

user_email 和 user_id 是要更新的用户的电子邮件和 ID。

我知道这里的问题是因为查询的语法不正确,它应该是“[ deleted_at ] IS NULL”而不是“= NULL”,但我不知道如何修复它。

QueryException 堆栈错误

php sql-server laravel 语法错误

评论

0赞 Lajos Arpad 10/31/2023
你如何触发它?如何指定该值应为 null?
0赞 Rafael Oliveira 10/31/2023
用户模型启用了“SoftDeletes”,因此Laravel会自动检查检索的用户是否未被删除,deleted_at = null,它适用于mysql,但不适用于mssql,因为语法不同。

答:

2赞 Lajos Arpad 10/31/2023 #1

一方面,SQL Server 不允许将

something = null

要使用。另一方面,当它被生成到查询中时,你发现了一个用例。

这是不可接受的,不仅是由于语法错误,而且是由于逻辑错误。MySQL允许你与事物进行比较,并将返回给你。nullnull

因此,您将需要考虑如何解决此问题。可能的解决方案

修复 Laravel 代码

这将确保你的代码与Laravel的官方代码不同,如果Laravel没有应用类似的修复程序,这将给你带来麻烦,但你可以联系Laravel的团队并告诉他们这个问题,他们可能会希望修复它。

创建数据库代理

可以编写一个 CLI 应用程序,该应用程序采用发送给它的任何命令行命令,将其转发到 SQL Server,并在获得响应时将其发送回颁发者。您可以自己实现这样的代理,也可以搜索现有的部分。

然后,此代理可以搜索

= null

在任何收到的查询中,并将其替换为 .IS NULL

使用视图

您可以为未删除的用户创建用户表视图,并在对未删除用户感兴趣时使用此视图。也许你可以有一个用于常见功能的 BaseUser 模型类。view

不使用软删除

还可以避免使用软删除,并自行实现相同的逻辑。

评论

0赞 Rafael Oliveira 10/31/2023
谢谢你的回复,Lajos。我在Laravel代码中做了一些测试,我能够解决这个问题,但这远非理想,因为我不确定由于我所做的更改,什么会破坏,当然,正如你所说,可能会导致未来的更新出现问题。我将看一下数据库代理解决方案,但我以前从未这样做过。使用视图或删除软删除不是一个选项,因为这是旧代码。
2赞 Stuck at 1337 10/31/2023
@RafaelOliveira你应该向Laravel抱怨,因为他们不应该为SQL Server生成语法。我会称之为一个非常严重的错误。= null
0赞 Rafael Oliveira 10/31/2023 #2

谢谢大家。多亏了 Laracast 论坛上的 Snapey,我才能够解决这个问题。由于 Laravel 验证,正在执行查询,但像这样编写验证会生成错误的查询。

'email' => 'required|email|string|max:255|unique:users,email,'.$this->id.',id,deleted_at,null',

将其更改为此可解决问题:

'email' => [
    'required',
    'email',
    'string',
    'max:255',
    Rule::unique('users')
            ->ignore($this->id)
            ->where(fn (Builder $query) => $query->whereNull('deleted_at' ))],

我不确定这是否是 Laravel 的问题,或者它是否打算像这样工作,但我认为简化的方式也应该有效并生成正确的查询。