2013-04-11 3 views
2

나는 4 개 테이블을 가지고있다.Laravel 관계 문제

정상적으로 작동하지만 실제로는 그렇지 않습니다. 생성 된 쿼리가 잘못된 결과를 반환합니다. 여기

내 모델 파일은 다음과 같습니다

<?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이지만 반환 된 쿼리에는 없습니다. 저를 보여주는, 그 항목이 빨간색이며, 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 번 쿼리하고 싶지 않습니다. 어떤 제안을 잘못 했나요?

편집 :아직 운이 없습니다. . :(내가, 당신이 나열된 변경을 완료 그들과 함께 실험을하지만이 일이 여전히 작동하지 않는 한 현재 오류가 있습니다 : 그것은 id를 찾는 이유

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

Bindings: array (
    0 => 0, 
) 

나도 몰라, 내가 변경했습니다 (

답변

1

쿼리 수 == 성능. 귀하의 경우 거의 원자적인 쿼리를 수행하고 있습니다 (where id in은 기본 인덱스와 비교하여 모두 수행됩니다. 빠른 결과를 얻을 수 있습니다 - 반환 결과 처리 시간을 제외하면 JOIN만큼 빠름). n + 1 쿼리 문제를 해결하고 싶다면, Eloquent는 이것을 해결할 수 있습니다 : ea 게르 - 로딩.대신이의

:

Shop_item::order_by('name') 

사용이 :

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

이를 사용하여 하나의 쿼리를 볼 수 있습니다. 이 기능에 대한 문서는 다음 위치에 있습니다. http://laravel.com/docs/database/eloquent#eager

+0

필자는 프론트 엔드 페이지에서 (주로) 필자가 필요하기 때문에 모델 파일에 $ include를 사용했다. 그러나 그것은 언급 된 분야에 대해 여전히 나에게 잘못된 결과를주었습니다. – peaks

+0

'return $ this-> has_one ('Shop_Category', 'id');'... 'id'를 고를 때'color '를 고르는 법을 알고 있다고 생각하십니까? –

+0

Phill의 코멘트에 대한 내 의견은 아래를 참조하십시오. – peaks

1

여기에는 많은 것들이 있습니다. 즉 color_id, size_idcategory_id 그래서

  1. 나는 ... 당신의 참고를 열 thing_id 이름을 것입니다. 이렇게하면 'sthing'대신 'color', 'size'및 'category'라는 관계를 설정할 수 있습니다.

  2. has_one() 대신 belongs_to()이 필요합니다. Laravel은 ID가 thing_id과 같다고 가정하므로 위의 1로 업데이트 한 경우 $this->belongs_to('Shop_Size')과 같은 참조를 업데이트 할 수 있습니다. 그렇지 않다면 $this->belongs_to('Shop_Size', 'size')처럼 여기에 참조 열을 사용해야합니다.

  3. Eloquent 모델을 사용할 때 열을 제한하지 않는 것이 가장 좋습니다. 모델에있는 논리에 따라 열이 달라질 수 있습니다.

  4. 쿼리를 향상시키기 위해 열망하는로드를 사용할 수 있지만 Eloquent의 작동 방식은 여전히 ​​관계 당 쿼리가 필요합니다.

    @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 
    

    이 대부분입니다 ... action_index()

    당신이보기에이 같은 코드를 작성할 수있을 것입니다 위의 모든 편집 후
    $items = Shop_Item::with(array('color', 'size', 'category')) 
            ->order_by('name')->paginate(10); 
    

이 라인에서보세요 특히 RelationshipsEager Loading과 같은 Eloquent 문서에서 다루어집니다.

+0

이것은 잘못된 의미의 결과를 얻는다는 의미에서 아무것도 변경하지 않습니다. 두 번째 테스트 항목이 잘못된 크기와 잘못된 색상을 가지기 때문에 잘못된 결과가 다시 나타납니다. (따라서이 값에 액세스하지 않고 전체 페이지 매기기가 문제가되지 않습니다.) – peaks

+0

내 모든 단계를 수행 했습니까? 숫자 2는 모든 관계가 쿼리에서 잘못된 ID를 얻는 이유이기 때문에 매우 중요합니다. 당신이 아무것도 바꾸지 않으면'$ this-> has_one ('Shop_Size', 'id')'~ $ this-> has_one ('Shop_Size', 'size')'(각 관계에 대해). –

+0

그러면 다음과 같이 끝낼 것입니다 : SQLSTATE [42S22] : 열을 찾을 수 없음 : 1054 'where 절에'colour '알 수없는 열 SQL : SELECT * FROM'item_colors' WHERE'color' IN (?,?) 바인딩 : 배열 ( 0 => 1, 1 => 2, 내가 할당 필드가 잘못된 열을 찾고 저를 보여 ) . – peaks