【问题标题】:How to delete single (many-) rows from one-to-many relations in Laravel 5.5如何从 Laravel 5.5 中的一对多关系中删除单个(多)行
【发布时间】:2018-05-22 22:04:57
【问题描述】:

我在 Laravel 中有两个模型:标签

class Label extends \Eloquent
{
    protected $fillable = [
        'channel_id',
        'name',
        'color',
    ];

    public function channel()
    {
        return $this->belongsTo('App\Channel');
    }
}

还有频道

class Channel extends \Eloquent
{
    protected $fillable = [
        'name',
    ];

    public function labels()
    {
        return $this->hasMany('App\Label');
    }

}

现在,当标签被删除时,我想确保该标签属于频道。

这很好用,因为它甚至是原子的,所以如果标签确实属于通道,那么该行将被删除。

标签控制器:

/**
 * Remove the specified resource from storage.
 *
 * @param  int $id
 * @return \Illuminate\Http\Response
 */
public function destroy($id)
{
    $channel = $this->getChannel();

    Label::where('id', $id)
        ->where('channel_id', $channel->id)
        ->delete();

    return back();
}

我现在的问题是:如何用 Eloquent 构建它,让它优雅?比如:

    $channel->labels()->destroy($id);

但是关系上没有销毁函数。

更新:

我设法朝着正确的方向取得了一些成就:

$channel->labels()->find($id)->delete();

这会删除带有 $id BUT 的标签,前提是标签分配了正确的 channel_id。如果没有,我会收到以下错误,我可以捕获并处理:

FatalThrowableError (E_ERROR) Call to a member function delete() on null

不过,由于 Apache 是线程化的,在我读取它之后,可能会有另一个线程更改 channel_id。那么除了我的查询之外唯一的方法就是运行一个事务?

【问题讨论】:

  • 您应该在数据库中创建外键,以便自动删除该行。
  • 我不是删除频道而是删除标签。实际上,有一个外键可以级联频道,但这无济于事,因为我没有删除频道。在 Laravel 的文档中,大多数时候只有一个 Post:destroy($id) 非常好,除了你想在安全问题方面检查另一个标志(user_id、channel_id 等)。
  • 我不明白你在做什么。为什么要检索频道$channel = $this->getChannel(); 并检查频道ID 是否与->where('channel_id', $channel->id) 匹配?第一条语句不应该使第二条语句过时吗?
  • 我的意思是:您通过这两个查询访问相同的数据。我认为目前没有额外的安全措施。
  • 我只是想知道是否有更优雅的方式来实现与使用 Laravel 对象的删除查询相同的功能。简单的方法是获取频道,检查标签中的 channel_id,然后销毁标签。然而,可能有另一个 Apache 进程更改了其间的 channel_id,因此 select 会成功,但 delete 会破坏不允许删除的行(不再)...

标签: php laravel eloquent one-to-many relation


【解决方案1】:

如果您想删除模型的相关项而不是模型本身,您可以这样做:

$channel->labels()->delete();会删除所有与频道相关的标签。

如果您只想删除部分标签,可以使用where()

$channel->labels()->where('id',1)->delete();

此外,如果您的关系是多对多的,它也会从第三个表中删除。

【讨论】:

  • 我收到一个错误? SQLSTATE[HY000]:一般错误:1205 超过锁定等待超时;尝试重新启动事务(SQL:从berkas 删除,其中berkas.p_id = 3 和berkas.p_id 不为空)
【解决方案2】:

您提到过,您首先要检查标签是否有频道。如果是这样,那么它应该被删除。

你可以试试这样的:

$label = Label::find($id);
if ($label->has('channel')) {
    $label->delete();
}

【讨论】:

  • 不,标签总是有一个频道。将其视为类似于 user_id 和一些访问管理的东西。总是有一个通道,但是当您将标签移动到另一个通道(中间)时,删除应该会失败(意味着什么都不做)。
【解决方案3】:

你可以使用 findorfail:

$channel->labels()->findOrFail($id)->delete();

【讨论】:

    猜你喜欢
    • 2018-08-13
    • 1970-01-01
    • 2018-06-27
    • 2018-03-16
    • 2019-02-02
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多