Laravel关系问题

时间:2013-04-11 13:14:19

标签: php mysql laravel eloquent laravel-3

我有4张桌子:

structure

我的关系应该像这样:

项目只能有一种尺寸,颜色和类别。

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

以下是我的模型文件:

<?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;
}

因此,当我尝试访问额外值(size-&gt; name,color-&gt; name,category-&gt; name)时,我得到错误的结果。

我的数据库中有两条测试记录: 项目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,我已经更改了对子表的所有引用并适当地重命名了列。 :(

2 个答案:

答案 0 :(得分:1)

查询数量!==效果。在您的情况下,您正在进行近乎原子的查询(where id in全部完成与主要索引,这将使它们变得快 - 如果排除返回结果处理时间,则与JOIN一样快。如果你想解决n + 1查询问题,Eloquent有一个解决方案:eager-loading。

而不是:

Shop_item::order_by('name')

使用此:

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

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

答案 1 :(得分:1)

这里有很多事情发生。

  1. 我会将您的参考列thing_id命名为...... color_idsize_idcategory_id。这将允许您设置名为“颜色”,“大小”和“类别”的关系,而不是“sthing”。

  2. 您需要belongs_to()而不是has_one()。 Laravel假定该ID与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);
    
  5. 完成上述所有编辑后,您就可以在视图中编写如下代码......

    @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