使用 Laravel ORM 抽象保存新的不可为空的关系,而不会违反数据库完整性约束

Posted

技术标签:

【中文标题】使用 Laravel ORM 抽象保存新的不可为空的关系,而不会违反数据库完整性约束【英文标题】:Save new non-nullable relationship using Laravel ORM abstraction without database integrity constraint violation 【发布时间】:2020-10-28 23:02:46 【问题描述】:

这个问题与 Laravel 7 有关。

我有两个模型,比如说 Post 和 Comment,它们是典型的一对多关系。定义了关系及其逆关系。在为他们的数据库表进行迁移时,我没有使 Comment 表上的 post_id 可以为空。我认为使其不可为空是一个合理的约束,因为所有评论都必须在逻辑上附加到帖子。

但是,在发表新评论时,我似乎无法使用create()save() 等来关联关系。我想做类似的事情:

$post->comments()->create(["text" => "Comment text goes here"]);

我会假设这会创建带有 post_id 填充的评论,但是很遗憾,它会在数据库级别引发“完整性约束违规”(post_id 不能为空)

同样,我试过了:

$comment = new Comment(["text" => "Comment text goes here"]); 
$post->comments()->save($comment); 

同样的事情 - 违反数据库完整性约束。但为什么?我希望 Laravel 在创建此评论时不会只进行一个包含 post_id 的 INSERT 操作。在这两种情况下,我都不希望在 post_id 为空的情况下插入新的评论。

我知道我可以在创建时手动将 post_id 设置为主键,如果确实没有其他选项,我会这样做 - 我更喜欢尽可能使用 ORM 抽象。

问题:

有谁知道save()create() 是否实际上是先在关系字段为空的情况下插入行,然后再更新 - 还是我只是做错了什么? 如果可能的话,使用 Eloquent ORM 抽象的正确方法是什么? 我一直觉得,由于我在 Comment 上定义了关系 post(),如果我使用 ORM,现在显式处理 post_id 列是不好的做法,因为它破坏了关系抽象的意义。这种哲学合理吗?我的想法是否正确?

注意:我知道this question 存在,但我认为我的不是重复的,因为在那个问题中,他们的 belongsTo 关系是可选的,所以他们接受了“只需删除 DB 约束/使列可为空”的答案. Mine 不是可选字段,因此将其设为可空是没有意义的。是的,更改数据库约束将“解决”问题,但我更喜欢保留完整性约束,因为 post_id=null 的评论会出现故障,因此最好在数据库级别 imo 上实现这一点。

【问题讨论】:

$post 是现有模型实例吗? @lagbox 我打算回答是的,但我想你刚刚想通了。在我用来测试它的代码中,$post 是现有模型实例,但我在调用 $post 上的 save() 之前尝试关联注释。所以当然 $post 还没有主键。谢谢你看到这个:O @lagbox 如果您想将其添加为答案,我会接受。 【参考方案1】:

确保$post 是“现有”模型实例。如果这是一个新实例,请务必保存它,这样它将有一个来自数据库的“id”,否则“id”将是null,它会尝试分配给相关记录的外键字段。

【讨论】:

以上是关于使用 Laravel ORM 抽象保存新的不可为空的关系,而不会违反数据库完整性约束的主要内容,如果未能解决你的问题,请参考以下文章

在 Laravel 5 迁移中使列不可为空

Laravel 保护列免受不可为空/默认值的批量分配

由于 SQL 异常错误,无法将电子邮件属性保存到 sql 中:“不允许空插入”,除非属性不为空??(ORM 代码优先)

不可为空的抽象变量能否在 KOTLIN 中引发空指针异常?

如何创建可以保存状态的不可为空的 LiveData

Laravel 更新模型而不是保存新的