2015-07-14 7 views
3

У меня есть таблицы БД региона (список городов), Аренда (список информации об аренде) и Rental_Location (список адресов аренды + lat/long).Laravel 5 Как получить связанные данные таблицы с помощью цепочки

Основные отношения:

Regions haveMany Rentals (with FK's region_id and rental_location_id in Rentals table) 
Locations haveMany Rentals, or the reverse logic Rental belongsTo a Location 

То, что я хотел бы сделать, это получить информацию о местонахождении всех аренды в регионе от region_id (из таблицы в аренду), а также включают в себя расположение пространственные данные (rental_locations таблица):

$region = Region::find(1); 
$rentals = $region->rentals; // doesn't contain location information yet 
$rentalDataWithSpatialLocationData = $region->rentals->location; // what I liked to do 

Но последняя строка, используя отношения belongsTo не будет работать, добавив пространственные данные из rental_locations в оригинальную коллекцию аренды.

В настоящее время коллекция $ rentals содержит все арендные платы для региона, но не содержит пространственных данных для маркировки местоположения на карте, но кроме использования объединения в QueryBuilder, что-то вроде этого ниже и не использует свойства ORM hasMany в мои модели:

$spatials = DB::table('rentals') 
       ->join('regions', 'rentals.region_id', '=', 'regions.id') 
       ->join('rental_locations', 'rentals.rental_location_id', '=', 'rental_locations.id') 
       ->where('rentals.region_id', '=', $region_id) 
       ->select('*') 
       ->get(); 

в принципе, я не могу понять, как получить коллекцию всех аренды с их информацией о местоположении, это возможно с помощью ORM? Похоже, что это может стать дорогим по сравнению с соединением, поэтому я предполагаю, что теперь вы не используете ORM для исключения QueryBuilder, но больше для дополнения простых и быстрых запросов отношений?

+0

Если у вас есть в вашем RegionModel функция rent(), которая возвращает hasMany отношения, она должна работать отлично. Является результатом $ region-> rentals - пустой или пустой коллекцией? – Danny

+0

Привет, @ Danny, извините, я, должно быть, объяснил это неправильно, мое плохое. $ Region-> rentals возвращает коллекцию всех арендных ставок, но мне также нужны пространственные данные из rent_locations. – mtpultz

+0

поэтому в основном у каждого Аренда есть несколько мест? – Danny

ответ

3

Здесь есть пара вещей, о которых вы должны знать.

Во-первых, для вашей исходной проблемы ваш код не будет работать, потому что вы пытаетесь получить доступ к атрибуту отношения на моделях аренды , а не отдельной модели. Если петля через Collection, вы могли бы получить доступ к location отношения по каждому отдельному пункту просто отлично:

$region = Region::find(1); 
$rentals = $region->rentals; // Collection of rentals for the region 
foreach($rentals as $rental) { 
    print_r($rental->location); // location info for the individual rental 
} 

Теперь, одна вещь, чтобы отметить о приведенном выше коде, что вы будете работать в то, что известно как проблема N + 1. По умолчанию Laravel lazy загружает объекты отношений, поэтому запросы для заполнения данных отношений не запускаются до тех пор, пока не потребуются атрибуты отношений. Игнорируя регион прямо сейчас, в приведенном выше коде, Laravel выполнит один запрос, чтобы получить всю арендную плату, а затем в цикле foreach он запустит новый запрос для каждой итерации цикла (N запросов), чтобы получить информацию о местоположении для каждая аренда; следовательно, N + 1 запросов.

Чтобы устранить эту проблему, вы можете с нетерпением загружать отношения. Пожелая загрузку, Laravel запускает один запрос, чтобы получить аренду, а затем один запрос, чтобы получить всю информацию о местоположении для всех арендных единиц, в общей сложности два запроса (вместо N + 1). Выбросьте информацию о регионе туда, и на самом деле это три запроса.

Для нетерпеливого нагрузки отношения, вы используете метод with() по запросу:

// eager load the rentals, and the nested location on the rentals 
// 1 query for region, 1 for all rentals on region, and 1 for all locations on rentals 
$region = Region::with('rentals', 'rentals.location')->find(1); 

// this is now accessing already loaded rentals; no lazy loading needed 
$rentals = $region->rentals; 

foreach($rentals as $rental) { 
    // this is now accessing already loaded locations; no lazy loading needed 
    print_r($rental->location); 
} 

Еще одно различие это делает, и то, что, возможно, сделали вы думаете, не имеют доступа к информации о местоположении, является что ленивые загруженные отношения не будут отображаться до тех пор, пока вы их не получите, тогда как нетерпимые загруженные отношения будут немедленно доступны. При отладке путем печати объектов на экран это может заставить вас думать, что вам не хватает данных, когда вы на самом деле нет.Что я имею в виду:

/** 
* lazy load relationships 
* This will only show the information for the region object. No 
* rental or location information will be shown as it has not been 
* loaded yet. 
*/ 
$region = Region::find(1); 
print_r($region); 

/** 
* eager load relationships 
* This will show the information for the region object, as well as 
* all of the related rental objects and their related location 
* information. 
*/ 
$region = Region::with('rentals', 'rentals.location')->find(1); 
print_r($region); 
+0

Привет, спасибо, что это блестяще, я сыграл с вашим примером в Tinker с find() прикованным и unchained, чтобы увидеть разные результирующие наборы. – mtpultz

+0

У меня есть аналогичный вопрос о том, как создавать/обновлять аренду - http://stackoverflow.com/q/31442013/1148107. Есть ли аналогичное решение с использованием ORM? Прямо сейчас я заштриховал решение с использованием QueryBuilder, которое работает, но я пытаюсь получить удобство с помощью ORM. – mtpultz

+0

Итак, это обеспечивает все данные, которые мне нужны в коллекции, и я обрезаю их перед отправкой обратно с помощью API-интерфейсов коллекций? Например, если мне нужна только широта и долгота для каждой аренды в rentals.location. – mtpultz

Смежные вопросы