我正在使用laravel 5.5,我有这个代码
$building = Building::findOrFail($building_id);
$units = $building->units()
->whereHas('parkingspaces',function($query) use($request){
$query->where('name','=', $request->search );
})
->orWhereHas('users',function($query) use($request){
$query->where('name','LIKE','%'.$request->search.'%');
})
->get();
我得到的结果是错误的,我希望它能够搜索建筑物单位的用户/租户名称。但它也会进入其他建筑物并进行搜索。所以我在结果中让其他建筑物出现了单位。
我认为通过设置 $ building ,可以使所有查询更深入搜索。
$building->units()->with(['users','parkingspaces'])->get();
,获取与用户和停车位相连的正确单位。
关于我做错了什么的任何线索?
注意:Auth::user()->current_building()
从会话中获取构建ID。
构建模型代码段
class Building extends Model{
public function users()
{
return $this->belongsToMany('App\User','buildings_users');
}
public function tenants(){
return $this->belongsToMany('App\User','buildings_users')->whereHas('roles', function ($query) {
$query->where('name', '=', 'resident');
});
}
public function staff(){
return $this->belongsToMany('App\User','buildings_users')->whereHas('roles',function($query){
$query->where('name','!=','tenant')->where('name','!=','administrator')->where('name','!=','superadministrator');
});
}
public function managers(){
return $this->belongsToMany('App\User','buildings_users')->whereHas('roles',function($query){
$query->where('name','=','manager');
});
}
public function units(){
return $this->hasMany('App\Unit');
}
单位模型代码段
class Unit extends Model
{
//
public function building(){
return $this->belongsTo('App\Building');
}
public function users(){
return $this->belongsToMany('App\User','user_unit');
}
public function parkingspaces(){
return $this->hasMany('App\Parkingspace');
}
building_users
CREATE TABLE IF NOT EXISTS `buildings_users` (
`building_id` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
user_unit
CREATE TABLE IF NOT EXISTS `user_unit` (
`building_id` int(10) unsigned NOT NULL,
`unit_id` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
单位摘录
CREATE TABLE IF NOT EXISTS `units` (
`id` int(10) unsigned NOT NULL,
`building_id` int(10) unsigned NOT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
parkingspaces
CREATE TABLE IF NOT EXISTS `parkingspaces` (
`id` int(10) unsigned NOT NULL,
`building_id` int(10) unsigned NOT NULL,
`unit_id` int(10) unsigned NOT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
答案 0 :(得分:1)
问题在于未分组的orWhereHas()
电话。
您的$building->units()
关系会构建一个类似以下内容的SQL查询:
select * from units
where
units.building_id = ?
and units.building_id is not null
然后,您将关系的条件添加到此基本查询中,因此您的查询最终会像:
select * from units
where
units.building_id = ?
and units.building_id is not null
and exists([parkingspaces query])
or exists([users query])
最后or
条件是您获得额外记录的原因。即使所有三个条件都为假,如果最后一个条件匹配,也会返回记录(false AND false AND false OR true === true
)。
您需要做的是将您的条件分组,以便or
条件适当确定范围(false AND false AND (false OR true) === false
)。您可以通过将闭包传递给where()
调用来完成此操作:
$units = $building->units()
->where(function ($query) use($request){
return $query
->whereHas('parkingspaces',function($query) use($request){
$query->where('name','=', $request->search );
})
->orWhereHas('users',function($query) use($request){
$query->where('name','LIKE','%'.$request->search.'%');
});
})
->get();
这将生成类似以下内容的查询:
select * from units
where
units.building_id = ?
and units.building_id is not null
and (
exists([parkingspaces query])
or exists([users query])
)
现在,您的or
条件的范围正确,您只能获得具有匹配ID的建筑物的结果。
答案 1 :(得分:0)
“has-many-through”关系提供了通过中间关系访问远程关系的便捷捷径。
$units = Auth::user()->units;
这样您就可以直接通过用户访问单位:
hasManyThrough
Laravel不会进行查询来访问用户的构建,然后再进行另一个查询来访问该构建的单元,而是使用带有连接的单个查询来获取成员。
{{1}}关系Laravel文档:image repository