【问题标题】:Laravel Removing Pivot data in many to many relationshipLaravel 删除多对多关系中的数据透视表
【发布时间】:2015-02-11 03:09:32
【问题描述】:

不确定我是否正确设置。在 Laravel 中,我正在创建两个具有多对可能关系的模型

型号为ItemTags。每个都包含一个belongsTo 到另一个。

当我像这样运行查询时:

Item::with('tags')->get();

它返回items 的集合,每个项目都包含一个tags 集合。然而,集合中的每个标签还包含我不需要的 pivot 数据。这里是json格式:

[{
    "id":"49",
    "slug":"test",
    "order":"0","tags":[
        {"id":"3","name":"Blah","pivot":{"item_id":"49","tag_id":"3"}},
        {"id":"13","name":"Moo","pivot":{"item_id":"49","tag_id":"13"}}
    ]
}]

有没有办法阻止这些数据进入

【问题讨论】:

  • 这是stackoverflow.com/questions/20887530/… 的明显重复项 - 请删除赏金,以便我们将其作为重复项关闭。
  • 这似乎只在我执行->toArray()->toJson() 时有效,但如果我只是打印出$item->tags,我仍然会在对象中看到枢轴数据。似乎它在进行不必要的查询,因为我没有尝试访问数据透视表中的任何数据。仍然想要一个答案。
  • 例如,如果我要直接通过枢轴编写查询:SELECT t.* FROM tags AS t JOIN city_tag AS ct WHERE ct.item_id = 111;
  • 不,API 应该是这样工作的。通过提供数据透视数据也不会浪费更多的资源(可能除了从数据库传输它们的带宽)。而且我认为您确实明白,除了 数据透视表 之外,没有其他方法可以实现多对多关系。 $hidden 是一个 API feature(Eloquent 的),因此只有在您使用 APItoArraytoJson)时才可用。对象的 PHP 转储显然会显示其中的所有信息。这里没有其他答案
  • Eloquent 生成的查询会接近这个:SELECT t.*, ct.* FROM tags AS t JOIN city_tag AS ct WHERE ct.item_id = 111; - 这里没有真正的性能损失...

标签: php laravel tags pivot-table


【解决方案1】:

您可以像这样在模型的隐藏部分中添加字段名称:

protected $hidden = ['pivot'];

就是这样,它对我来说很好。

【讨论】:

  • 这适用于整个模型,但我怎样才能只使用一种方法呢?谢谢
【解决方案2】:

你已经问过了,你会得到你的答案。但先说几句话来总结评论部分。我个人不知道你为什么想要/需要这样做。我了解您是否想hide it from the output 但不从数据库中选择它确实没有真正的好处。当然,传输的数据更少,数据库服务器要做的工作也少了一点点,但你不会注意到这一点。

但这是可能的。不过它不是很漂亮,因为您必须覆盖 belongsToMany 类。

一、新的关系类:

class BelongsToManyPivotless extends BelongsToMany {
    /**
     * Hydrate the pivot table relationship on the models.
     *
     * @param  array  $models
     * @return void
     */
    protected function hydratePivotRelation(array $models)
    {
        // do nothing
    }

    /**
     * Get the pivot columns for the relation.
     *
     * @return array
     */
    protected function getAliasedPivotColumns()
    {
        return array();
    }
}

如您所见,这个类覆盖了两个方法。 hydratePivotRelation 通常会创建数据透视模型并用数据填充它。 getAliasedPivotColumns 将返回一个包含所有列的数组以从数据透视表中选择。

现在我们需要将其集成到我们的模型中。我建议您为此使用 BaseModel 类,但它也可以直接在模型中使用。

class BaseModel extends Eloquent {

    public function belongsToManyPivotless($related, $table = null, $foreignKey = null, $otherKey = null, $relation = null){
        if (is_null($relation))
        {
            $relation = $this->getBelongsToManyCaller();
        }

        $foreignKey = $foreignKey ?: $this->getForeignKey();

        $instance = new $related;

        $otherKey = $otherKey ?: $instance->getForeignKey();

        if (is_null($table))
        {
            $table = $this->joiningTable($related);
        }

        $query = $instance->newQuery();

        return new BelongsToManyPivotless($query, $this, $table, $foreignKey, $otherKey, $relation);
    }
}

为了简洁起见,我编辑了 cmets,但除此之外,该方法就像来自 Illuminate\Database\Eloquent\ModelbelongsToMany。当然,除了创建的关系类。这里我们使用我们自己的BelongsToManyPivotless

最后,这就是你如何使用它:

class Item extends BaseModel {
    public function tags(){
        return $this->belongsToManyPivotless('Tag');
    }
}

【讨论】:

  • 但是为什么会这样呢?你在你的模型中只需要这个:protected $hidden = ['pivot'];
  • 我可以给出一个需要的情况:使用 Postgresql,如果 select 包含分组操作(SUM,COUNT),则要求所有列都有分组操作或出现在 GROUP BY 中。在这里,额外的数据透视列会产生“分组错误”,例如参见 stackoverflow.com/questions/16012818/postgresql-grouping-error
  • 太棒了,@Amine_Dev!我一直在寻找这个答案……太简单了!
  • 另一个用例是unions,您可以在其中获得SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of columns
【解决方案3】:

如果你想删除数据透视数据,那么你可以按照protected $hidden = ['pivot'];@Amine_Dev 的建议使用,所以我使用了它,但它对我不起作用,

但问题确实是我在错误的模型中使用它,所以我想在其中提供更多详细信息,说明在哪里使用它,这样你们就不用为我一直在努力的问题而苦恼了。

因此,如果您将数据提取为:

Item::with('tags')->get();

然后您必须将枢轴分配给隐藏数组,如下所示

但请记住,您必须在 Tag 模型中而不是在 Item 模型中定义它

class Tag extends Model {

   protected $hidden = ['pivot'];
}

【讨论】:

    【解决方案4】:

    两种可能的方法

    1.在结果模型上使用 makeHidden 方法

    $items = Item::with('tags')->get();
    return $items->makeHidden(['pivot_col1', 'pivot_col2']...)
    

    2。使用 PHP 的 array_column 函数

    $items = Item::with('tags')->get()->toArray();
    
     return array_column($items, 'tags');
    

    【讨论】:

      猜你喜欢
      • 2023-02-05
      • 2018-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-29
      • 1970-01-01
      • 2014-12-07
      • 1970-01-01
      相关资源
      最近更新 更多