[英]Laravel 5 How to retrieve related table data using chaining
I've got DB tables of Region (list of cities), Rental (list of rental information), and Rental_Location (list of rental addresses + lat/long). 我有地区(城市列表),租赁(租赁信息列表)和Rental_Location(租赁地址列表+纬度/长)的数据库表。
The basic relationships are: 基本关系是:
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
What I'd like to do is get the location information of all the rentals in a region from a region_id (from the rentals table), as well as include the location spatial data (rental_locations table): 我想要做的是从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
But the last line using the belongsTo relationship won't work by adding the spatial data from rental_locations into the original rentals collection. 但是使用belongsTo关系的最后一行将无法通过将rental_locations中的空间数据添加到原始租赁集合中。
Right now the $rentals collection contains all the rentals for a region, but no spatial data to mark the location on a map, but other than using a join in QueryBuilder something like this below and not using the ORM hasMany properties in my models: 现在$ rental集合包含一个区域的所有租赁,但没有空间数据来标记地图上的位置,但除了在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();
Basically, I can't figure out how to get a collection of all the rentals with their location information, is this possible using the ORM? 基本上,我无法弄清楚如何使用其位置信息获取所有租赁的集合,这是否可以使用ORM? Seems like this might get expensive compared to a join, so I'm assuming right now you don't use the ORM to the exclusion of the QueryBuilder, but more to supplement simple and quick relationships queries only?
看起来这样比连接可能会变得昂贵,所以我现在假设您不使用ORM来排除QueryBuilder,而只是补充简单和快速的关系查询?
There are a couple things going on here that you should know about. 这里有几件你应该知道的事情。
First, for your original issue, your code won't work because you're trying to access the relationship attribute on a Collection
of rental models, and not an individual model. 首先,对于您的原始问题,您的代码将无法运行,因为您尝试访问租赁模型
Collection
上的关系属性,而不是单个模型。 If you loop through the Collection
, you would be able to access the location
relationship on each individual item just fine: 如果您遍历
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
}
Now, one thing to note about the code above is that you will be running into what is known as the N+1 problem. 现在,有关上述代码的一点需要注意的是,您将遇到所谓的N + 1问题。 By default, Laravel lazy loads the relationship objects, so the queries to populate the relationship data are not run until the relationship attributes are needed.
默认情况下,Laravel延迟加载关系对象,因此在需要关系属性之前,不会运行填充关系数据的查询。 Ignoring the region for right now, in the code above, Laravel will run one query to get all the rentals, and then in the foreach loop, it will run a new query for each loop iteration (N queries) to get the location information for each rental;
暂时忽略该区域,在上面的代码中,Laravel将运行一个查询以获取所有租借,然后在foreach循环中,它将为每个循环迭代(N个查询)运行新查询以获取位置信息每次出租; hence N+1 queries.
因此N + 1个查询。
To alleviate this problem, you can eager load the relationships. 要缓解此问题,您可以急切加载关系。 By eager loading, Laravel will run one query to get the rentals, and then one query to get all the location information for all the rentals, for a total of two queries (instead of N+1).
通过急切加载,Laravel将运行一个查询来获取租金,然后运行一个查询以获取所有租赁的所有位置信息,总共两个查询(而不是N + 1)。 Throw the region information back in there and it is actually three queries.
将区域信息重新放回那里,实际上是三个查询。
To eager load the relationships, you use the with()
method on the query: 要急切加载关系,可以在查询中使用
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);
}
Another difference this makes, and what may have made you think you didn't have access to the location information, is that lazy loaded relationships won't show up until you access them, whereas eager loaded relationships are immediately available. 这样做的另一个不同之处是,您可能认为自己无法访问位置信息,因为延迟加载的关系在您访问它们之前不会显示,而急切加载的关系立即可用。 When debugging by printing the objects to the screen, this could make you think you're missing data when you're really not.
通过将对象打印到屏幕进行调试时,这可能会让您认为当您真的没有时会丢失数据。 What I mean by that is this:
我的意思是:
/**
* 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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.