2

我有 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,我已经更改了对子表的所有引用并适当地重命名了列。:(

4

2 回答 2

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

于 2013-04-11T13:27:00.680 回答
1

这里发生了很多事情。

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

  2. 你需要belongs_to()而不是has_one(). Laravel 假设 ID 是 like thing_id,所以如果你已经更新为上面的 1 ,那么你可以更新你的引用,比如$this->belongs_to('Shop_Size')。如果没有,那么您应该在此处使用参考列,例如$this->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

于 2013-04-11T13:28:44.390 回答