我有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;
}
因此,当我尝试访问额外值(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,我已经更改了对子表的所有引用并适当地重命名了列。 :(
答案 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)
这里有很多事情发生。
我会将您的参考列thing_id
命名为...... color_id
,size_id
和category_id
。这将允许您设置名为“颜色”,“大小”和“类别”的关系,而不是“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文档中,尤其是Relationships和Eager Loading。