36

私は Laravel を使用しており、Eloquent ORM で小さな問題を抱えています。JOIN を使用して SQL クエリで簡単に動作させることができますが、Eloquent では動作しないようです!

これが私が欲しいものです。2 つのテーブルがあります。1 つは「Restaurants」で、もう 1 つは「Restaurant_Facilities」です。

テーブルは単純で、1 対 1 の関係です。、 、 などのrestaurantテーブルとidname、、などでslug呼び出される別のテーブルがあるようにrestaurant_facilitiesidrestaurant_idwifiparking

今私がやりたいことは..wifi = 1またはwifi = 0のすべてのレストランをロードすることです..どうすればEloquentでそれを行うことができますか? 熱心な読み込み、ピボット テーブル、with()、collections() を試しましたが、何もうまくいかないようです!

の多対多の関係で私が抱えているのと同じ問題cuisines! 私は同じrestaurantテーブルとテーブルとテーブルcuisineを持っていrestaurant_cuisine_connectionます..

しかし、その ID を使用して特定の料理内のすべてのレストランを読み込むにはどうすればよいですか?

これは機能します。

Cuisine::find(6)->restaurants()->get();

しかし、私はレストランからこれをロードしたい:: 料理からではなくモデル.. 多くの条件が一緒に連鎖しているため.. 検索およびフィルタリング/閲覧ページ用です。

アイデアや方法はありますか?私はこれに3日間苦労してきましたが、まだ答えがありません。

モデル例:

class Restaurant extends Eloquent {

    protected $table = 'restaurants';

    public function facilities() {
        return $this->hasOne('Facilities'); 
    }
}

class Facilities extends Eloquent {

    protected $table = 'restaurants_facilities';

    public function restaurant() {
        return $this->belongsTo('Restaurant');
    }

}

PS: これは機能しているようですが、これは雄弁な方法ではありませんか?

Restaurant::leftJoin(
                'cuisine_restaurant', 
                'cuisine_restaurant.restaurant_id', 
                '=', 'restaurants.id'
             )
             ->where('cuisine_id', 16)
               ->get();

また、別のクエリなしで特定の列の値を持つレストランの数を見つけるための最良の方法は何ですか? のように.. 駐車場が 1 で Wi-Fi が 1 のレストランの合計を見つけなければなりませんか?

これについて助けてください。

ありがとうございました。

4

5 に答える 5

34

Restaurant モデルからロードする必要がある場合、ここで左結合を実行しても問題はないと思います。次のように、Restaurant モデルのメソッドに抽象化できます。

class Restaurant extends Eloquent {
    protected $table = 'restaurants'; // will be default in latest L4 beta

    public function facility()
    {
      return $this->hasOne('Facility');
    }

    // Or, better, make public, and inject instance to controller.
    public static function withWifi()
    {
      return static::leftJoin(
        'restaurant_facilities',
        'restaurants.id', '=', 'restaurant_facilities.restaurant_id'
      )->where('wifi', '=', 1);
    }
}

そして、あなたのルートから:

Route::get('/', function()
{
  return Restaurant::withWifi()->get();
});

外出先で - そのコードをテストしていませんが、動作するはずです。代わりに、制約付きの熱心な読み込みを使用できますが、それは施設オブジェクトが null かどうかのみを指定します。where 句を指定しない限り、すべてのレストランが返されます。

(追伸: 私は施設の単数形を使い続けたいと思います。どのようhasOne('Facilities')に正しく読めないことに注意してください?)

于 2013-01-31T12:33:43.810 に答える
20

新しい共有パラダイムを構築する際に REST API 方法論を改善しようとしていたときに、この投稿に出くわしました。Eager Loading Constraintsを使用したい。共有アイテムをロードする api ルートがあり、それが次のようなサブアイテムのコレクションであるとします。

/api/shared/{share_id}/subitem/{subitem_id}

GET リクエストでこのルートにヒットするときは、その特定のサブアイテムをロードする必要があります。その ID でそのモデルをロードすることもできますが、そもそもユーザーがその共有アイテムにアクセスできるかどうかを検証する必要がある場合はどうでしょうか? 1 つの回答では、逆の関係を読み込むことを推奨していましたが、これにより、コントローラーがすぐに混乱して混乱する可能性があります。熱心なロードで制約を使用することは、より「雄弁な」アプローチです。したがって、次のようにロードします。

$shared = Shared::where('id', $share_id)
  ->with([ 'subitems' => function($query) use ($subitem_id) {
    $query->where('subitem_id', $subitem_id)
  }]);

したがって、そのIDを持つサブアイテムのみが必要な場合。次のようにして、それが見つかったかどうかを確認できます。

if ($shared->subitems->isEmpty())

subitems はコレクション (サブアイテムの配列) であるため、次のように subitem[0] を返します。

return $shared->subitems[0];
于 2014-09-30T17:24:00.503 に答える
15

whereHas任意の関係でフィルタリングするために使用します。リレーションには参加しませんが、関連するプロパティによって現在のモデルをフィルタリングします。このような状況に役立つローカルスコープも調べてください https://laravel.com/docs/5.3/eloquent#local-scopes

あなたの例は次のようになります。

Restaurant::whereHas('facilities', function($query) {
    return $query->where('wifi', true);
})->get();


Restaurant::whereHas('cuisines', function($query) use ($cuisineId) {
    return $query->where('id', $cuisineId);
})->get();

ローカルスコープで同じことを達成するには:

class Restaurant extends Eloquent
{
    // Relations here

    public function scopeHasWifi($query)
    {
        return $query->whereHas('facilities', function($query) {
            return $query->where('wifi', true);
        });
    }

    public function scopeHasCuisine($query, $cuisineId)
    {
        return $query->whereHas('cuisines', function($query) use ($cuisineId) {
            return $query->where('id', $cuisineId);
        });
    }
}

ローカル スコープの場合、モデルで静的メソッドとして定義しないでください。これにより、クエリ ビルダーの新しいインスタンスが作成され、メソッドの連鎖が妨げられます。ローカルスコープを使用すると、クエリビルダーの現在のインスタンスが挿入されて返されるため、必要な数のスコープをチェーンできます。

Restaurant::hasWifi()->hasCuisine(6)->get();

ローカル スコープは、メソッド名にプレフィックスを付けて定義され、上記の例のようにメソッド名scopeなしで呼び出されます。scope

于 2016-11-10T18:12:53.933 に答える
10

whereHas()関数を主演する別のソリューション:

$with_wifi = function ($query) {
   $query->where('wifi', 1);
};

Facilities::whereHas('restaurant', $with_wifi)

きちんと整頓されています。

于 2015-11-13T18:03:56.453 に答える
1

Restaurant モデルから絶対にロードする必要がありますか? 問題を解決するために、私は通常、逆にアプローチします。

Facilities::with('restaurant')->where('wifi' ,'=', 0)->get();

これにより、条件に一致するすべてのレストラン施設が取得され、レストランが熱心に読み込まれます。

さらに条件を連鎖させて、このように合計を数えることができます..

Facilities::with('restaurant')
  ->where('wifi' ,'=', 1)
  ->where('parking','=', 1)
  ->count();

これなら料理にも合いそう

Cuisine::with('restaurant')->where('id','=',1)->get();

これは、この料理を提供するすべてのレストランをロードした 1 の熱心な ID を持つ料理オブジェクトを取得します

于 2013-01-31T13:19:10.617 に答える