首页 文章

Laravel关系问题

提问于
浏览
2

我有4张 table :

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-> name,color-> name,category-> 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 }}

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

Edit: 仍然没有运气 . :(我已经完成了你列出的更改,用它们进行了实验但是这个东西仍然没有用 . 目前的错误是:

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

Bindings: array (
  0 => 0,
)

我没有't know why it looks for an id, I'已经更改了对子表的所有引用并适当地重命名了列 . :(

2 回答

  • 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

    这里有很多事情要发生 .

    • 我会将您的参考列命名为 thing_id ...所以这是 color_idsize_idcategory_id . 这将允许您设置名为'color','size'和'category'的关系,而不是'sthing' .

    • 您需要 belongs_to() 而不是 has_one() . Laravel假设ID类似于 thing_id ,所以如果你已经更新为1,那么你可以更新你的引用,如 $this->belongs_to('Shop_Size') . 如果没有,那么你应该在这里使用参考列,如 $this->belongs_to('Shop_Size', 'size') .

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

    • 您可以使用预先加载来改进查询,但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 .

相关问题