【问题标题】:Lighthouse GraphQL - HasManyThrough on pivot tableLighthouse GraphQL - 数据透视表上的 HasManyThrough
【发布时间】:2021-02-22 21:52:39
【问题描述】:

我有一个项目,我正在从 Rails REST API 转换为 Laravel GraphQL API(我是 Laravel 的新手),并且正在设置模型和关系。

我有一个categoriescategory_itemsitems 表。

category_items 表包含 category_iditem_idposition 的列。

items 表有一列用于category_id

当我打开 artisan tinker 并运行 App\Models\Category::find(1)->items()->get(); 时,它会返回所有预期的内容(包括嵌套在 Item 对象下方的数据透视表)。但是,当我在 graphql-playground 中运行它时,我得到了错误:

"debugMessage": "SQLSTATE[42S02]: Base table or view not found: 1146 Table 'my_project.category_item' doesn't exist (SQL: select * from `category_item` where 0 = 1)",

我有一种感觉,我忽略了一些微小的东西,就像我不知道的错字或命名约定一样。

我还想做的是在项目对象中包含来自数据透视表的position 列。本质上,我不想将“位置”列嵌套在项目的枢轴内,而是希望将“位置”作为项目对象的一部分包含在内,但是我不确定这是否可能。

Schema.graphql

type Query {
    categories: [Category!]! @field(resolver: "CategoriesQuery@find_by_user")
    items: [Item!]! @field(resolver: "ItemsQuery@find_by_user")
    notifications: [Notification!]! @field(resolver: "NotificationQuery@find_by_user")
}

type Category {
    id: ID!
    name: String!
    created_at: DateTime!
    updated_at: DateTime!

    category_items: [CategoryItem!]! @hasMany
    items: [Item!]! @belongsToMany
}

type CategoryItem {
    id: ID!
    position: Int!
    created_at: DateTime!
    updated_at: DateTime!

    categories: [Category!]! @hasMany
    items: [Item!]! @hasMany
}

type Item {
    id: ID!
    name: String
    quantity: Int
    created_at: DateTime!
    updated_at: DateTime!

    categories: [Category]! @belongsToMany
    category_item: CategoryItem! @belongsTo
}

Category.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Category extends Model
{
    protected $fillable = [
        'name'
    ];

    // automatically eager load items of a category
    protected $with = ['items'];

    // define relationships
    public function category_items(): HasMany
    {
        return $this->hasMany(CategoryItem::class);
    }

    public function items(): BelongsToMany
    {
        return $this
            ->belongsToMany('App\Models\Item', 'category_items', 'item_id', 'category_id')
            ->using('App\Models\CategoryItem')
            ->withPivot(['position'])
            ->withTimestamps();
    }
}

CategoryItem.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Eloquent\Relations\HasMany;

class CategoryItem extends Pivot
{
    protected $fillable = [
        'category_id', 'item_id', 'position'
    ];

    // public function category(): HasMany
    // {
    //     return $this->hasMany(Category::class);
    // }

    // public function item(): HasMany
    // {
    //     return $this->hasMany(Item::class);
    // }
}

Item.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Item extends Model
{
    protected $fillable = [
        'name', 'price', 'category_id', 'quantity'
    ];

    // define relationships
    public function categories(): BelongsToMany
    {
        return $this
            ->belongsToMany('App\Models\Category', 'category_items', 'item_id', 'category_id')
            ->using('App\Models\CategoryItem')
            ->withPivot(['position'])
            ->withTimestamps();
    }

    public function category_item(): BelongsTo
    {
        return $this->belongsTo('App\Models\CategoryItem');
    }
}

总结一下,我的问题是:

  1. 是什么导致了 Playground 中的 GraphQL 错误?
  2. 是否可以将透视表属性附加到其直接父对象?

【问题讨论】:

  • 您通常不需要为数据透视表创建模型,但如果您愿意,您需要指定表名,因为您使用的是非标准名称。 protected $table = 'category_items'; 数据透视表应该按字母顺序用单数命名,所以category_item.
  • 你知道,我实际上是在文档中读到的,它导致了其他错误,所以我保留了它。我可以开始沿着这条路线再次测试它。不过以防万一,我会将protected $table 应用于哪个模型?另外,您是说表名本身应该是“category_item”而不是“category_items”?因为我所有的表都是复数形式的:“categories”、“category_items”、“items”....这只是 Rails 命名约定,而在 Laravel 中这些都应该是单数形式吗?
  • 好的,只需仔细检查源代码,是的,数据透视模型确实需要一个单数表名,因此您应该将该属性放入您的 CategoryItem 模型定义中。抱歉编辑混乱,我不应该怀疑自己!
  • 一切都好,感谢您的帮助!它修复了原来的错误,但是现在我得到了Cannot return null for non-nullable field Item.category_item

标签: laravel eloquent graphql laravel-lighthouse


【解决方案1】:

@miken32 帮了大忙。我删除了不必要的 CategoryItem.php 模型,将 db 表从 category_items 重命名为 category_item,并在我的 schema.graphql 中重新定义了以下类型:

type Category {
    id: ID!
    name: String!
    created_at: DateTime!
    updated_at: DateTime!

    pivot: CategoryItemPivot
    items: [Item!]! @belongsToMany
}

type CategoryItemPivot {
    id: ID!
    position: Int!
    created_at: DateTime!
    updated_at: DateTime!

    categories: [Category!]! @hasMany
    items: [Item!]! @hasMany
}

type Item {
    id: ID!
    name: String
    quantity: Int
    created_at: DateTime!
    updated_at: DateTime!

    categories: [Category!]! @belongsToMany
    pivot: CategoryItemPivot
}

【讨论】:

    猜你喜欢
    • 2015-09-10
    • 1970-01-01
    • 2018-03-05
    • 2021-01-22
    • 2016-09-04
    • 2016-08-04
    • 2021-08-24
    • 1970-01-01
    • 2015-12-09
    相关资源
    最近更新 更多