Laravel Eloquent ManyToMany with Pivot,在数据透视表中包含变量的辅助查询?

时间:2019-02-10 08:07:58

标签: php laravel eloquent

我一直在玩laravel,遇到了一个我不太清楚的怪异案例

我具有以下表结构:

CREATE TABLE `community_address` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `address_id` int(10) unsigned NOT NULL,
  `community_id` int(10) unsigned NOT NULL,
  `is_billing` tinyint(1) NOT NULL DEFAULT '1',
  `is_service` tinyint(1) NOT NULL DEFAULT '1',
  `is_mailing` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
)

CREATE TABLE `communities` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
)

CREATE TABLE `addresses` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `address_1` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Street address',
  `address_2` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Street adddress 2 (Company name, Suite, etc)',
  `city` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'City',
  `state` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'State / Province',
  `zip` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Zip / Postal Code',
  `country_id` int(10) unsigned NOT NULL COMMENT 'Country ID',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
)

我曾为社区使用以下Laravel模型

class Community extends Model
{
    public function addresses(){
        return $this->belongsToMany(Address::class, 'community_address', 'community_id',  'address_id');
    }
}

$ community-> addresses()实际上仅返回社区的地址,但是说我想按数据透视表中的地址类型(计费,邮寄等)进行过滤

我可以尝试:

   public function getBillingAddress(){
        return $this->addresses()->wherePivot('is_billing','=', true)->firstOrFail()->get();
    }

哪个会返回结果,但是它是我的数据透视表中的每行都与我的查询匹配,而不是在现有地址之外运行我的查询

所以我的第二个想法是像这样使用'and'布尔参数

 public function getBillingAddress(){
        return $this->addresses()->wherePivot('community_id', '=', $this->id, true)->wherePivot('is_billing','=', true)->firstOrFail()->get();
    }

哪个会导致以下SQL错误(出于明显的原因)出错,但即使它确实起作用了,也看起来并不太像我在寻找我想要的东西?

select `addresses`.*, `community_address`.`community_id` as `pivot_community_id`, `community_address`.`address_id` as `pivot_address_id` from `addresses` inner join `community_address` on `addresses`.`id` = `community_address`.`address_id` where `community_address`.`community_id` = 2 1 `community_address`.`community_id` = 2 and `community_address`.`is_billing` = 1 limit 1 

在我看来,“ and”值实际上不是布尔值,而是将值直接打印为查询的字符串。

我尝试了显而易见的方法,并尝试将第四个参数与“ and”交换,并生成了以下sql,它不会失败,但是会返回所有地址,而不仅仅是返回链接到我的社区的地址

select `addresses`.*, `community_address`.`community_id` as `pivot_community_id`, `community_address`.`address_id` as `pivot_address_id` from `addresses` inner join `community_address` on `addresses`.`id` = `community_address`.`address_id` where `community_address`.`community_id` = 2 and `community_address`.`community_id` = 2 and `community_address`.`is_billing` = 1 limit 1)

我在这里缺少明显的东西吗?

通过对结果SQL进行一些修改,我可以得到我想要的,这是以下原始sql查询:

select `addresses`.*,
       `community_address`.`community_id` as `pivot_community_id`,
       `community_address`.`address_id`   as `pivot_address_id`
from `addresses`
       inner join `community_address` on `addresses`.`id` = `community_address`.`address_id` and `community_address`.`community_id` = 2 and `community_address`.`is_billing` = 1
limit 1

如何通过雄辩地实现为我生成相同的SQL?

2 个答案:

答案 0 :(得分:1)

如果我想出一个例子,我认为这对您来说将是一个完整的用户 我们有用户 角色 Role_User 表 我们已将用户连接到角色,并属于属于我们,并且我们要使用select:

用户模型:

function Roles()
{
 return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
}

在我们的控制器中,我们可以像下面这样写任何选择:

class exampleController extends Controller
{
public function index()
{
User::with(['Roles'=>function($query){$query->where(....)->get();}])->get(); 
}

}

您可以在查询中使用任何选择,然后返回您想要的任何内容。

如果您需要在选择中使用任何变量,请务必小心 波纹管格式

class exampleController extends Controller
{
public function index()
{
$var =...;
User::with(['Roles'=>function($query) use ($var){$query->where(....,$var)->get();}])->get(); 
}

}

我希望这能解决您的问题...

答案 1 :(得分:0)

似乎我误解了wherePivot()的工作方式,将代码更改为以下工作方式:

   public function getBillingAddress(){
        return $this->addresses()->wherePivot('is_billing', '=', true)->get()->first->all();
    }

在新代码试图调用数据透视表的is_billing列以进一步过滤现有表的情况下,旧代码试图通过已被其过滤的内容对其进行过滤,但是由于它是内部联接,因此它正在返回所有行(至少我认为?)

无论哪种方式,这个问题都可以解决,希望这对以后的人有所帮助。