Laravel从错误的行中提取信息?说明?

问题描述 投票:0回答:2

我正在使用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;

停车位

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;
laravel
2个回答
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的建筑物的结果。


0
投票

“has-many-through”关系提供了通过中间关系访问远程关系的便捷捷径。

// In your User model
public function units()
{
    return $this->hasManyThrough(Unit::class, Building::class);
}

这样您就可以直接通过用户访问单元:

$units = Auth::user()->units;

Laravel不使用查询来访问用户的构建,然后再进行另一个查询来访问该构建的单元,而是使用带有连接的单个查询来获取成员。

hasManyThrough关系Laravel docs:https://laravel.com/docs/5.3/eloquent-relationships#has-many-through

© www.soinside.com 2019 - 2024. All rights reserved.