php - Laravel 5 如何使用链接检索相关表数据

标签 php mysql laravel eloquent laravel-5

我有 Region(城市列表)、Rental(租赁信息列表)和 Rental_Location(租赁地址列表 + 纬度/经度)的数据库表。

基本关系是:

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(来自 rentals 表)获取一个区域中所有出租的位置信息,以及包括位置空间数据(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 集合包含一个区域的所有租金,但没有空间数据来标记 map 上的位置,但除了在 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,而是更多地仅补充简单快速的关系查询?

最佳答案

这里有几件事你应该知道。

首先,对于您的原始问题,您的代码将不起作用,因为您正试图访问 Collection 租赁模型的关系属性,而不是单个模型。如果您遍历 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 延迟加载关系对象,因此在需要关系属性之前不会运行填充关系数据的查询。现在忽略区域,在上面的代码中,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);

关于php - Laravel 5 如何使用链接检索相关表数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31413553/

相关文章:

php - 子部分未将样式注入(inject)其父 Blade 布局

php - 格式化用 PHP 创建的 XML 文档 - DOMDocument

MYSQL:如何在 mysql GROUP BY 查询中返回所有不同的行

MySQL,根据值选择列名

php - Laravel 5 全局日期访问器

php - 在 php 脚本中访问发布的 Json 数据

laravel - Sentry 2、修改密码功能

php - Laravel/PHP str_replace 函数中的单引号显示笑脸图像

mysql - 如何获取 Laravel 和 mysql 的较低日期

php - 什么是模板语言?