Laravel Eloquent $model->save() 方法无法保存数据但没有报错。

40

当我更新我的Post模型时,我运行以下代码:

$post->title = request('title');
$post->body = request('body');

$post->save();

根据Laravel更新Eloquent模型的文档,这不会更新我的帖子。但是应该更新。 为什么我的模型没有被更新?

Post模型:

class Post extends Model
{
    protected $fillable = [
        'type',
        'title',
        'body',
        'user_id',
    ];

   ....
}

帖子 控制器:

public function store($id)
{
    $post = Post::findOrFail($id);

    // Request validation
    if ($post->type == 1) {
        // Post type has title
        $this->validate(request(), [
            'title' => 'required|min:15',
            'body' => 'required|min:19',
        ]);

        $post->title = request('title');
        $post->body = request('body');
    } else {
        $this->validate(request(), [
            'body' => 'required|min:19',
        ]);

        $post->body = request('body');
    }

    $post->save();

    return redirect('/');
}

奖励信息

运行dd($post->save())返回true

运行

$post->save();

$fetchedPost = Post::find($post->id);
dd($fetchedPost);

这告诉我$fetchedPost是之前的同一篇文章,但没有更新的数据。


@AndersonAndrade 它返回了 false ...... 我按照这个 Stack Overflow 的问题来确保我做得正确。 - Jacob
{btsdaf} - Lars Mertens
1
{btsdaf} - Moeen Basra
这与文章类型有什么关系呢?如果文章类型不等于1,那么你就没有设置标题,但是标题是一个必填字段。 - kerrin
对我有效的方法是在我的模型中设置一个受保护的属性$primaryKey。 - taavs
显示剩余15条评论
14个回答

23

如果 'id' 列以大写的 'ID' 表示,请检查您的数据库表。将其更改为小写后,我的 save() 方法可以正常工作。


12
您无需更改它,只需在模型中添加 protected $primaryKey = 'Id'; 来定义主键名称即可。这种情况适用于主键是“Id”而不是“id”。 - Junior
1
这是我的问题,我正在处理一个已经存在的数据库,其中ID不被称为Id或ID,而是完全不同的东西。这使得很难发现,因为我正在使用protected $primaryKey ='myid';,并且它可以正常工作进行查询,但如果不是完全匹配,它将无法保存。我的表的ID是大写的,改变它,问题就解决了,你的评论让我看到了问题所在。 - Gary
该死的MSSQL不区分大小写!找到了模型但Eloquent无法正确保存。 - Marcos Regis
不要更改数据库,而是从 protected $primaryKey = 'Id'; 模型更改值。 - TarangP
我的mysql USER_ID被大写了,但我设置了$primaryKey = 'user_id'。一切都完美地运行,除了无法保存到数据库。将其大写化解决了问题。谢谢! - PhillipMcCubbin

16

我也遇到了同样的问题,最后发现是因为我在过滤输出列时没有使用主键。

$rows = MyModel::where('...')->select('col2', 'col3')->get();
foreach($rows as $row){
    $rows->viewed = 1;
    $rows->save();
}

固定了

$rows = MyModel::where('...')->select('primary_key', 'col2', 'col3')->get();

经过审查后,这个意思非常清楚:如果没有可用的主键,更新命令将会是空值。


这也是我的问题原因。谢谢! - Michael Horn
这也困扰了我。必须确保在模型中包含主键,以便使用 save() 进行更新。从未知道这一点。 - HartleySan
是的,这就是我的问题,我也忘记了主键 :) 谢谢! - Alex Boscan

7

我曾经也遇到过同样的问题,改变模型获取的方式解决了它!

尽管一切看起来都应该按照你所提到的方式工作,但数据却没有被保存:

$user = User::find($id)->first(); 

这是有效的:

$user = User::find($id);

记住,在某些情况下,使用find方法与save方法一起使用是有效的,但在其他情况下,save方法不起作用...同时要记住,find方法只使用primaryKey。 - Mateus Gonçalves

6

您需要确保在调用save()时,实例具有id属性。


1
在所展示的代码中,他正在执行 $post = Post::findOrFail($id);,因此必须设置一个 id。 - Miguel G. Flores

4
DB::transaction 内运行 dd() 会导致回滚并且数据库中的数据不会改变。这是因为事务会在最后才将更改保存到数据库。因此,运行 "dump and die" 将自然导致脚本停止执行,从而没有对数据库进行任何更改。

4

自Laravel 5.5以来,Laravel已更改了一些验证机制,我猜您需要尝试这种方式。

public function store(Request $request, $id)
{
    $post = Post::findOrFail($id);

    $validatedData = [];

    // Request validation
    if ($post->type == 1) {
        // Post type has title
        $validatedData = $request->validate([
          'title' => 'required|min:15',
          'body' => 'required|min:19',
      ]);
    } else {
      $validatedData = $request->validate([
        'body' => 'required|min:19',
    ]);
    }

    $post->update($validatedData);

    return redirect('/');
}

{btsdaf} - Moeen Basra

3

如果您的主键不是"id",请检查您的表格("列名只能使用小写字母")。如果您设置了具有不同键的列名,则在您的模型中放置以下代码:

protected $primaryKey   = 'Id';

所以,在你的情况下,这可能是其中一个可能的解决方案,特别是如果你的列名包含大写字母。 是的,这对我也起作用了。 你的列名应该是小写的。 如果你没有,那么在模型文件中提到它,主要是针对primaryKey,通过它,你的模型将尝试访问数据库。


2

如果数据库的主键不是 "id",则使用 save () 方法来 更新删除 数据时,需要在模型中声明属性 primaryKey = "" ,这样才能正常工作。


1

我遇到了同样的问题,虽然在controller@action()中有try / catch块,但没有响应,它只停留在$model->save();,apache的error.loglaravel.log中也没有日志条目。我刚刚用以下方式包装了save(),这帮助我找出了问题。

    try{
        $model->save();
    }
    catch (\PDOException $e) {
        echo $e->getMessage();
    }

0

根据我的经验,如果你从数据库中选择一个 Eloquent 模型,并且 primary_key 列不是被获取的列之一,那么你的 $model->save() 将会返回 true,但是没有任何东西被保存到数据库中。

因此,不要使用 \App\Users::where(...)->first(['email']),而是使用 \App\Users::where(...)->first(['id','email']),其中 id 是目标表上定义的 primary_key

如果仅通过检索少量列来实现(有时微小的优化)并不重要,那么你可以通过执行 \App\Users::where(...)->first() 来获取所有列,在这种情况下,你不需要担心 primary_key 列的名称,因为所有列都将被获取。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接