laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.2k stars 10.89k forks source link

hasManyThrough relation creating query with wrong values when localKey is other than 'id' #15909

Closed sudhirk496 closed 6 years ago

sudhirk496 commented 7 years ago

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.

themsaid commented 7 years ago

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.

sudhirk496 commented 7 years ago

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'.

himtuna commented 7 years ago

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.

laurencei commented 6 years ago

Looks like this has been fixed in Laravel 5.5