2016-03-16 4 views
0

Я создаю приложение, которое имеет projects и проекты имеют plot_types.Laravel 5 выбрать только данные отношений по hasMany отношения

Я хочу, чтобы проверить, существует ли объект plot_type в текущем проекте.

У меня есть следующий код:

$testResult = $project->with(['plotTypes' => function($query) use ($row) { 
      $query->where('name', $row->plot_name); 
     }])->first() 

Это производит следующие MySQL:

select exists(select * from `projects` where exists (select * from `projects_plot_types` where `projects_plot_types`.`project_id` = `projects`.`id` and `name` = ?)) as `exists` 

Этот SQL возвращает строки, которые не связаны с $project объекта. Например, когда я dd($project) я получаю:

#attributes: array:11 [▼ 
    "id" => "4" 
    "name" => "xxx" 
    "number" => "1234" 
    "builder" => "1" 
    "overall_budget" => "3456.00" 
    "start_date" => "2016-03-31" 
    "end_date" => "2016-04-30" 
    "created_date" => "2016-03-16 15:22:05" 
    "updated_date" => "2016-03-16 15:22:07" 
    ] 

Тем не менее, когда я dd($testResult); это дает;

#relations: array:1 [▼ 
"plotTypes" => Collection {#767 ▼ 
    #items: array:1 [▼ 
    0 => ProjectsPlotTypes {#770 ▼ 
     #table: "projects_plot_types" 
     #fillable: array:2 [▶] 
     +timestamps: false 
     #connection: null 
     #primaryKey: "id" 
     #perPage: 15 
     +incrementing: true 
     #attributes: array:4 [▼ 
     "id" => "1" 
     "project_id" => "1" 
     "name" => "TYPE 1 - VENTILATION" 
     "budget" => "324.67" 
     ] 

Обратите внимание, project_id выше показывает 1. Это не связано с текущим проектом, поскольку текущий идентификатор проекта равен 4.

Почему это происходит?

ответ

1

Это одна из тех потенциально запутанных частей модели ActiveRecord. Все экземпляры модели содержат те же методы, которые используются для извлечения экземпляров модели, поэтому легко думать, что что-то должно работать в одном направлении, когда это действительно не так.

Вызов $project->with(), это то же самое, что и звонок Project::with(). Даже если вы вызываете with() на экземпляр проекта, он не собирается ограничивать загруженные объекты только теми, которые связаны с вашим экземпляром.

Когда вы вызываете $project->with(), первое, что он делает, это создать новый запрос для всех проектов, а затем добавить в нетерпеливую загрузку. Затем вы вызываете first(), который просто получает первую запись проекта и все ее загруженные объекты.

Чтобы получить типы сюжетов для вашего конкретного проекта, у вас есть пара вариантов.

  1. Просто запросите отношения. $project->plotTypes() дает базовый запрос для всех типов сюжетов, связанных с вашим проектом. Вы можете добавить свои ограничения и получить записи оттуда.

    $plotTypes = $project->plotTypes()->where('name', $row->plot_name)->get(); 
    dd($plotTypes); 
    
  2. нагрузки связанные типы сюжетных с ограничениями:

    // assume your project doesn't have any plottypes loaded yet 
    $project = Project::find(1); 
    
    // load the plottypes relation with constraints 
    $project->load(['plotTypes' => function($query) use ($row) { 
        $query->where('name', $row->plot_name); 
    }]); 
    dd($project->plotTypes); 
    
  3. фильтр уже загружен Collection соответствующих типов участков. $project->plotTypes имеет все типы сюжетов, связанные с вашим проектом, но вы можете использовать метод where() на Collection (отличный от where() по запросу) для фильтрации записей в Collection.

    // assume your project already has all plotTypes loaded 
    $project = Project::with('plotTypes')->find(1); 
    
    // you just want to get a subset of those pre-loaded plottypes 
    $plotTypes = $project->plotTypes->where('name', $row->plot_name); 
    dd($plotTypes); 
    
+1

Великолепный ответ, большое вам спасибо! – V4n1ll4

0

Используйте метод whereHas сделать фильтрацию вместо того, чтобы с

$testResult = $project->whereHas('plotTypes' => function($query) use ($row) { 
     $query->where('name', $row->plot_name); 
})->with('plotTypes')->first(); 

И кроме того, вы хотите получить все связанные записи или только первый запись?

если все затем изменить первые() к Get()

Надеется, что это помогает

+0

Я попытался это, но она по-прежнему не дает ожидаемого результата. Если я делаю 'first()', он дает мне связь с 2 plotTypes, но оба они не привязаны к текущему проекту. – V4n1ll4

+0

сначала измените внутренний запрос $ на $ query-> где ('name', '=', $ row-> plot_name); и посмотрим, что произойдет. second Log :: info ($ row-> plot_name) и посмотреть, содержит ли он что-то – oseintow

Смежные вопросы