【问题标题】:Laravel relationship problemsLaravel 关系问题
【发布时间】:2013-04-03 16:56:09
【问题描述】:

我有 4 张桌子:

我的人际关系应该是这样的:

商品只能有一种尺寸、颜色和类别。

这应该有效,但实际上并非如此。生成的查询返回错误的结果。

这是我的模型文件:

<?php

class Shop_Item extends Eloquent
{
    public static $table = 'items';
    public static $timestamps = false;

    public function scategory() {
        return $this->has_one('Shop_Category','id');
    }

    public function ssize() {
        return $this->has_one('Shop_Size','id');
    }

    public function scolor() {
        return $this->has_one('Shop_Color','id');
    }
}

其余表的其余模型文件相同(表名和模型名除外)。

<?php
class Shop_Category extends Eloquent
{
    public static $table = 'item_categories';
    public static $timestamps = false;
}

所以当我尝试访问额外的值(大小->名称、颜色->名称、类别->名称)时,我得到了错误的结果。

我的数据库中有两条测试记录: 项目 1 和项目 2 具有不同的颜色、尺寸和类别。 项目 1 为蓝色,尺寸为 M, 项目 2 是绿色的,大小为 XL,但不在返回的查询中。这告诉我,第 2 项是红色的,大小为 S。

控制器:

<?php

class Admin_Shop_Controller extends Base_Controller {

    public function action_index() {

        $items = Shop_item::order_by('name')->paginate(10,array('id','name','price','sex','visible','color','size','category'));
        return View::make('admin.shop.index')->with('items', $items);
    }

查看:

@forelse($items->results as $i)
{{ $i->name }}
{{ $i->price }}
{{ $i->sex }}
{{ $i->scategory->name }}
{{ $i->scolor->name }}
{{ $i->ssize->name }}

<a href = "{{ URL::to('admin/shop/edit/'.$i->id) }}">Edit</a>
<a href = "#">Delete</a>

@empty
    There are no items in the shop.
@endforelse

生成的查询:

0.23ms  
SELECT COUNT(`id`) AS `aggregate` FROM `items`
0.28ms  
SELECT `id`, `name`, `price`, `sex`, `visible`, `color`, `size`, `category` FROM `items` ORDER BY `name` ASC LIMIT 10 OFFSET 0
0.25ms  
SELECT * FROM `item_categories` WHERE `id` IN ('1', '2')
0.21ms  
SELECT * FROM `item_sizes` WHERE `id` IN ('1', '2')
0.36ms  
SELECT * FROM `item_colors` WHERE `id` IN ('1', '2')

请注意,如果我像这样从另一个表中访问这些值,则在视图中:

{{ Shop_Color::find($i->color)->name }}

它让我得到了正确的结果,但我真的不想因为这个而查询数据库 n+3 次。任何建议我做错了什么?

编辑: 还是没有运气。 :( 我已经完成了您列出的更改,并对其进行了试验,但这仍然无法正常工作。当前错误是:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'id' in 'where clause'
SQL: SELECT * FROM `item_colors` WHERE `id` IN (?)

Bindings: array (
  0 => 0,
)

我不知道它为什么要查找 id,我已经更改了对子表的所有引用并适当地重命名了列。 :(

【问题讨论】:

    标签: php mysql laravel eloquent laravel-3


    【解决方案1】:

    查询数!== 性能。在您的情况下,您正在执行近乎原子的查询(where id in 与主索引相比都已完成,这将使它们快速 - 如果排除返回结果处理时间,则与 JOIN 一样快)。如果你仍然想解决 n+1 查询问题,Eloquent 有一个解决方案:急切加载。

    而不是这个:

    Shop_item::order_by('name')
    

    使用这个:

    Shop_item::with(array("scategory", "ssize", "scolor"))->order_by('name')
    

    您应该只看到一个查询。此功能的文档位于:http://laravel.com/docs/database/eloquent#eager

    【讨论】:

    • 我做了,但在模型文件中使用了 $include,因为(主要)我在前端页面上需要这些。但它仍然给我提到的字段错误的结果。
    • return $this-&gt;has_one('Shop_Category','id'); ...当你告诉它选择id时,你真的认为它会知道如何选择color吗?
    • 在下面查看我对 Phill 评论的评论。
    • 我已经在下面发表了评论,但我也会在这里添加 - 你想要 belongs_to() 而不是 has_one()。
    【解决方案2】:

    这里发生了很多事情。

    1. 我会将您的参考列命名为 thing_id... 所以这是 color_idsize_idcategory_id。这将允许您设置名为“颜色”、“尺寸”和“类别”的关系,而不是“东西”。

    2. 您需要belongs_to() 而不是has_one()。 Laravel 假设 ID 类似于 thing_id,所以如果你已经更新为上面的 1,那么你可以更新你的引用,比如 $this-&gt;belongs_to('Shop_Size')。如果没有,那么您应该使用此处的参考列,例如$this-&gt;belongs_to('Shop_Size', 'size')

    3. 当您使用 Eloquent 模型时,最好不要限制列 - 您的模型中可能有依赖于它们都存在的逻辑。

    4. 您可以使用预先加载来改进查询,但是 Eloquent 的工作方式仍然需要每个关系的查询。看看这条线action_index()

      $items = Shop_Item::with(array('color', 'size', 'category'))
                        ->order_by('name')->paginate(10);
      

    完成上述所有编辑后,您将能够在视图中编写类似这样的代码...

    @forelse ($items->results as $item)
    
        <p>Color: {{ $item->color->name }}</p>
    
    @else
        <p class="no-results">There are no items in the shop.</p>
    @endforelse
    

    Eloquent 文档中涵盖了大部分内容,尤其是 RelationshipsEager Loading

    【讨论】:

    • 从某种意义上说,这不会改变任何事情,我仍然会得到错误的结果。正如我所说,我得到了错误的结果,因为我的第二个测试项目得到了错误的尺寸和错误的颜色。 (所以不访问这些值并对整体进行分页不是问题。)
    • 您按照我的所有步骤操作了吗?第 2 点非常关键,因为这就是为什么您的所有关系都在查询中获取错误 ID 的原因。如果您没有更改任何其他内容,则应将 $this-&gt;has_one('Shop_Size', 'id') 更改为 $this-&gt;has_one('Shop_Size', 'size')(对于每个关系)。
    • 最终我会这样:SQLSTATE[42S22]:找不到列:1054 'where 子句'中的未知列'color' SQL:SELECT * FROM item_colors WHERE color IN ( ?, ?) Bindings: array ( 0 => 1, 1 => 2, ) 这表明我在那里分配的字段正在寻找错误的列。
    • 啊,当然……你需要使用belongs_to() 而不是has_one()(它们在 Laravel 中有点落后)。
    猜你喜欢
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 2017-02-07
    • 2015-06-18
    • 2017-04-28
    • 2017-11-09
    • 2018-08-28
    相关资源
    最近更新 更多