1

I am working in yii2.

There are employee and company table employee contains company_id.

I have a filter search running properly If I use joinWith()

  $query = Employee::find();
  $query->joinWith(['company']);

    $dataProvider = new ActiveDataProvider([
        'query'         => $query, 
        'pagination'    => false, 
        'sort'          => false,
    ]);


    if (!($this->load($params) && $this->validate())) {
        return $dataProvider;
    }

  //and below is the filterwhere
 $query->andFilterWhere(['like', 'company.name', $this->company_id]);

But issue came when I make a query using with()

$query = Employee::find()->with(['company']);

    $dataProvider = new ActiveDataProvider([
        'query'         => $query, 
        'pagination'    => false, 
        'sort'          => false,
    ]);


    if (!($this->load($params) && $this->validate())) {
        return $dataProvider;
    }

//when query contain with() then this filter is not working.
$query->andFilterWhere(['like', 'company.name', $this->company_id]);

This gives error when I use with()

Database Exception – yii\db\Exception
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'company.name' in 'where clause'
The SQL being executed was: SELECT COUNT(*) FROM `employee` WHERE `company`.`name` LIKE '%1%'

Here is the relation in employee with company:

public function getCompany(){
    return $this->hasOne(Company::className(),  ['id'=> 'company_id']);
}

Can anyone help me or guide me how could I filter data properly using with() in a query? Thanks.

always-a-learner
  • 3,671
  • 10
  • 41
  • 81

1 Answers1

3

You can't swap joinWith() and with() methods when you need to filter by the column from the related table. That's because these methods does completely different things.

Methods like joinWith() and join() actually modifies the query to add the "JOIN" part to the SQL query. The with in joinWith allows you to specify the joined table by the relation definition in the model. The eager loading in joinWith is only side effect and you can even turn that off by passing false as second parameter.

When you do:

Employee::find()->joinWith(['company'])->all();

The query that is run looks like:

SELECT * FROM employee LEFT JOIN company ON (...)

On the other side the method with() doesn't modify the query itself. It only forces the eager loading of related models. In reality the second query is used for preloading the related records. When you do:

Employee::find()->with(['company'])->all();

It actually runs queries like these:

SELECT * FROM employee;

SELECT * FROM company WHERE id IN (...company ids selected in first query...);

So when you try to do:

$query = Employee::find()
    ->with(['company'])
    ->andFilterWhere(['like', 'company.name', $this->company_id])
    ->all();

The generated query is

SELECT * FROM employee WHERE company.name LIKE ...
Michal Hynčica
  • 5,038
  • 1
  • 12
  • 24
  • the query which you gave here is also not working. It gives back the same error. I have tried to add `with()` in the `andFilterWhere` – always-a-learner Apr 22 '20 at 06:01
  • @always-a-learner I said in the first sentence that you can't swap `with()` and `joinWith()`. I've tried to explain how both of them are working so you can see why it is impossible to swap them. TLDR is that `with()` doesn't do a `JOIN` so you can't use columns from the other table to filter the results. – Michal Hynčica Apr 22 '20 at 06:11
  • yes sir I got that but the only thing which I don't understand is like the `with()` is getting the correct data on my gird view and like the same that data I want to filter then it not working. if data can be available for the view they whey not for the filter. – always-a-learner Apr 22 '20 at 07:48
  • 1
    @always-a-learner that's because the data for the grid are loaded in two separate queries. First the data for `Employee` models from table `employee` are selected. Then data for related `Company` models from `company` table are selected in the second independent query. The filter is applied on the first query where the columns from company table are not available. – Michal Hynčica Apr 22 '20 at 08:21
  • 1
    Technically you can load all models with `all()`. Then you can filter them by yourself with `array_filter()` or something similar. Finally you will use `yii\data\ArrayDataProvider` for grid. But this solution is much more complicated, slower and it will use more memory than `joinWith()`. – Michal Hynčica Apr 22 '20 at 08:22