Framework: hasManyThrough relation creating query with wrong values when localKey is other than 'id'

Created on 14 Oct 2016  路  4Comments  路  Source: laravel/framework

  • Laravel Version: 5.1.*
  • PHP Version: 5.5.9
  • Database Driver & Version: postgres 9.5.4

    Description:

hasManyThrough relation returns empty array always when localKey is not 'id'
Added listener to illuminate.query event and found that in 'where in' instead of localKey the id values are passed.

Output:
(
[0] => select "table_3".*, "table_2"."table_1_id" from "table_3" inner join "table_2" on "table_3"."id" = "table_3"."table_2_id" where "table_2"."table_1_id" in (?, ?, ?) and "table_2"."table_1_id" = ?
[1] => Array
(
[0] => 5
[1] => 7
[2] => 8
[3] => 14
)

[2] => 1.9
[3] => pgsql

)

Steps To Reproduce:

1.)
table_1: id,name,slug,group_id
table_2: id,name,table_1_id -- table_1_id = table_1.group_id
table_3: id,name,link,table_2_id -- table_2_id = table_2.id

2.)
table_1 Model relation:
public function table3()
{
return $this->hasManyThrough(TableThree::class, TableTwo::class,
'table_1_id', 'table_2_id', 'group_id');
}

3.)
TableOne::with(['table3' => function ($q) {
$q->where('table_2.table_1_id', 14);
}]);

In my table_1 for id's 5,7,8 group_id is 14.
When I execute step 3 I see above output but I have specifically mentioned the group_id as localKey.

Most helpful comment

I am also facing similar issues.

Here is my Database structure
district
-id (system generated)
-code

block
-id
-code
-name
-district_code (foreign key)

village
-id
-code
-block_code

Village belongs to Block. Block Belongs to District. I want to use hasManyThrough to call all villages in a district. Here is my District model. And I want to use 'code' instead of system generated 'id' field.

public function villages(){
  return $this->hasManyThrough(
    Village::class, Block::class, 
    'district_code','block_code','code');
}

This is the sql equery laravel runs.

select villages.*, blocks.district_code from villages inner join blocks on blocks.id = villages.block_code where blocks.district_code = 2201

Laravel takes local key as 'id' and not as specified in the argument.

All 4 comments

I can't replicate this issue, and the examples you share aren't really clear, there's no way I can know if these records aren't correct (7, 8, 14).

Please share a sql dump for the database you're using to test.

sql dump:

[https://drive.google.com/file/d/0B1l7ZPs3sATkOGhyaDRTNmZnYm8/view?usp=sharing]

Models:

Vacancy extends Model 
{
    protected $table = 'vacancy';

    public function ops_mapping()
    {
        return $this->hasOne(VacancyOpsMapping::class, 'vacancy_id', 'id');
    }
}

VacancyOpsMap extends Model 
{
    protected $table = 'vacancy_ops_map';

    public function totalCandidates()
    {
        return $this->hasManyThrough(VacancyCandidateLink::class, VacancyJackalMapping::class,
        'assignee_ops_id', 'vacancy_jackal_map_id', 'assigned_ops_id');
    }
}

Query:

Vacancy::with('ops_mapping.totalCandidates')->get()->toArray();

Queries generated:

(
    [0] => select * from "vacancy"
    [1] => Array
        (
        )

    [2] => 0.9
    [3] => pgsql
)
</pre><pre>Array
(
    [0] => select * from "vacancy_ops_map" where "vacancy_ops_map"."vacancy_id" in (?, ?, ?)
    [1] => Array
        (
            [0] => 6
            [1] => 8
            [2] => 9
        )

    [2] => 0.97
    [3] => pgsql
)
</pre><pre>Array
(
    [0] => select "vacancy_candidate_link".*, "vacancy_jackal_map"."assignee_ops_id" from "vacancy_candidate_link" inner join "vacancy_jackal_map" on "vacancy_jackal_map"."id" = "vacancy_candidate_link"."vacancy_jackal_map_id" where "vacancy_jackal_map"."assignee_ops_id" in (?, ?, ?)
    [1] => Array
        (
            [0] => 5
            [1] => 7
            [2] => 8
        )

    [2] => 1.01
    [3] => pgsql
)

This returns vacancies with ops_mapping.total_candidates as empty array.

The values 5,7,8 are id's in 'vacancy_ops_map' table, instead it should be 14 which is 'assigned_ops_id' in 'vacancy_ops_map' table. localKey mentioned in relation is 'assigned_ops_id'.

I am also facing similar issues.

Here is my Database structure
district
-id (system generated)
-code

block
-id
-code
-name
-district_code (foreign key)

village
-id
-code
-block_code

Village belongs to Block. Block Belongs to District. I want to use hasManyThrough to call all villages in a district. Here is my District model. And I want to use 'code' instead of system generated 'id' field.

public function villages(){
  return $this->hasManyThrough(
    Village::class, Block::class, 
    'district_code','block_code','code');
}

This is the sql equery laravel runs.

select villages.*, blocks.district_code from villages inner join blocks on blocks.id = villages.block_code where blocks.district_code = 2201

Laravel takes local key as 'id' and not as specified in the argument.

Looks like this has been fixed in Laravel 5.5

Was this page helpful?
0 / 5 - 0 ratings

Related issues

progmars picture progmars  路  3Comments

Fuzzyma picture Fuzzyma  路  3Comments

gabriellimo picture gabriellimo  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments

RomainSauvaire picture RomainSauvaire  路  3Comments