Related Search Behavior

There is actually a function in Yii for it (http://www.yiiframework.com/doc/api/1.1/CGridView#enableHistory-detail ) with limitations.

HOwever, I am using the same[size=2] ‘ERememberFiltersBehavior’ which I add automatically in my models using gii. [/size]

To fix the other extension, we need to consider that the sort key is in ‘sortVar’ . You are correct: sorting does not work correctly. I don’t see it at first sight - I think that RSB is doing it the right way, and the way RFB works needs some investigation.

I had version 1.2 of ERememberFiltersBehavior, but apparently that did not have the sort functionnality which explains why I couldn’t see it. The latest (same) 1.2 version does have it.

Basically ERememberFiltersBehavior relies on the name of the sort variable as provided by CActiveDataProvider which relies on CDataProvider where it is a combination of the DataProvider’s id which by default is the model class name.

So ideally, ERemberFiltersBehavior should get the $_GET key in the same way, but I can’t figure a way to do so at this time.

So, I modified RelatedSearchBehavior to rely on CActiveDataProvider and hence provide the expected sortVar in most cases.

The update is on the extension page.

Wowwwwww!

Awesome. It works very nice now. Thanks so much for changing this.

gb5256

Thanks for sharing this extension which seems very awesome. However did someone try it with postgresql ?? cause I never succeeded to use it…

EDIT:

get working with postgresql finally, However still in trouble with MANY_MANY relationships.

It doesn’t work when I set in behavior function :

‘my_name’=>‘myMANY_MANYrelation.anyField’

it displays nothing.

Moreover, I got problem with sorting my column through HAS_MANY relations, I have an error ’ missing FROM-clause entry for table “myHAS_MANYrelationship” ’ with the request send :

SELECT "t"."id" AS "t0_c0" FROM "mainTable" "t" GROUP BY t.id ORDER BY "myHAS_MANYrelation"."field" LIMIT 10;

The extension is awesome ;-), and it should work with postgresql which you ended up doing.

Is ‘myHAS_MANYrelation’ an existing relation in the active record? That is, ‘myHAS_MANYrelation’ must be the name of the relation defined for ‘mainTable’.

You write ‘myHAS_MANYrelationship’ and ‘myHAS_MANYrelation’. The latter is without ‘ship’ for instance so the name is not the same.

thanks for reply, anyway I get it working however I have problem coming from KeenLoading I guess. In group by I have only t.id… but as I have belongs_to relation sql tell me it miss my_relation.id in group by.

Moreover, my many_many relation works well with filering but sorting it gives same error that it misses a my_relation.id in group by.

I tried to deal it without your extension and just with keenloading extension and I have the same problem. I guess there is something wrong when keenLoading extension has to get the primary keys of relations’s table. It takes only t.id… well I guess.

Hi

I do not think the identification of the issue is correct here.

Using ‘KeenLoading’ alone with relations and witout RelatedSearchBehavior will hav you run into mssing configurations for the relations. The functionnality that you seem to be looking for works well for me in MySql or Sqlite so I do not see a reason why that would be different in postgresql.

If you can manage to repeat your issue in the demo environment, it would be easier to share it and hence to study it. The demo demonstrates sorting on fields that are in a relation.

Let’s take an example :

I have four tables : author(id,name,nationality_id) / author_genre(id,author_id,genre_id) / genre(id,genre_name) / nationality(id,name);

relations :

in author model : "genres" => array(self::MANY_MANY, "genre", "author_genre(author_id,genre_id)")

"from" => array(self::BELONGS_TO, "nationality", "nationality_id")

in genre : "authors" => array(self::MANY_MANY, "author", "author_genre(genre_id,author_id)")

in author_genre : "genre" => array(self::BELONGS_TO, "genre", "genre_id")

"author" => array(self::BELONGS_TO, "author", "author_id")

Here is my method search, the best way I found to get my many_many relationship working with filter and pager. Unfortunately I never succeed to get sorting working with my hisGenre column because I have an error as it misses "genres.id" in the group by.




$criteria=new CDbCriteria;

    $criteria->with=array('genres'=>array('select'=>false));

    //$criteria->limit=-1;

    $criteria->together=true;


    $criteria->compare('t.id',$this->id);

    $criteria->compare('t.name',$this->enabled);

    $criteria->compare('genres.id',$this->hisGenre);


    return new KeenActiveDataProvider(get_class($this), array(

        'pagination'=>array(

          'pageSize'=> Yii::app()->user->getState('pageSize',Yii::app()->params['defaultPageSize']),

        ),

        'withKeenLoading' => array('genres'),

        'criteria'=>$criteria,

        'sort'=>array('defaultOrder'=>'t.id ASC','attributes'=>array('assignedRole'=>array('asc'=>'genres.id','desc'=>'genres.id DESC'),'*')),

    ));

        }



Then I had the necessary to display the nationality as :




$criteria=new CDbCriteria;

    $criteria->with=array('genres'=>array('select'=>false),'from');

    //$criteria->limit=-1;

    $criteria->together=true;


    $criteria->compare('t.id',$this->id);

    $criteria->compare('t.name',$this->enabled);

    $criteria->compare('genres.id',$this->hisGenre);

    $criteria->compare('from.name',$this->isFrom);


    return new KeenActiveDataProvider(get_class($this), array(

        'pagination'=>array(

          'pageSize'=> Yii::app()->user->getState('pageSize',Yii::app()->params['defaultPageSize']),

        ),

        'withKeenLoading' => array('genres'),

        'criteria'=>$criteria,

        'sort'=>array('defaultOrder'=>'t.id ASC','attributes'=>array('assignedRole'=>array('asc'=>'genres.id','desc'=>'genres.id DESC'),'isFrom'=>array('asc'=>'from.name', 'desc'=>'from.name desc'),'*')),

    ));

        }



And with that I always have on this page an error as it misses from.id in group by… but If I add in KeenLoading extension by hand line 200 : $pkNames[] .="from.id";

Then I get something working for displaying, sorting and filtering for the column “isFrom” but I didn’t succeed to get sorting working for hisGenre column. Because if I add “genres.id” in group by then pager doesn’t work anymore… for Gridview displays not all objects…

I created a topic here if you wand to read more about my problem and try to help me. I tried a lot of thing but never get all working correctly =) thanks

http://www.yiiframework.com/forum/index.php/topic/44838-filter-and-sort-a-column-fed-by-a-many-many-relation/page__gopid__213109#entry213109

Hi

I now see the issue: you are not (fully) using the extension !

You should define a ‘relation’ that you call ‘hisGenre’ (or whatever), us that as the column name/value, and then RelatedSearchbehavior does the magic.

In stead of doing:


   $criteria->compare('genres.id',$this->hisGenre); 




you should


public function rules()

	{

  return array(

 		// .. other rules


// Related field aliases allowed during search.

 		array('hisgenre', 'safe', 'on'=>'search'),

		);

	}


public function behaviors() {

      return array(

               // Add RelatedSearchBehavior

               'relatedsearch'=>array(

                       'class'=>'RelatedSearchBehavior',

                       'relations'=>array(

                                 'hisGenre'=>'genres.id',

                              ),

              ),

	    );

	}




Check out ‘protected/models/Invoiceline.php’ of the demo and ‘protected/views/site/index.php’ of the demo.

You can see that there are only the ‘compare’ statements for the native fields in ‘search()’. The other ‘compare’ statements are provided by RelatedSearchBehavior! When the ‘CGridView’ column parameter says ‘Composer’, this in fact looks for ‘track.Composer’, and when it says ‘SupportLastName’ it looks for ‘invoice.customer.support.FirstName’ which is several relations deep. And you can even do $model->SupportLastName to get the value of that relation.

I guess there is too much magic in RelatedSearchBehavior - too little to write for a lot of "hidden" functionnality.

I’m not fully using the extension because it doesn’t work with postgresl or with many_many relation I don’t know. I looked at your demo but I didn’t see any many_many relations, but i guess that’s not the problem. Anyway I tried what you suggested and I exactly copy what you’ve done in your demo as you told me to look at… it doesn’t work…

However I manage it to get it work without your extension only with keenloading which allows me to have only one request to get my genres for each author instead of N.




$criteria=new CDbCriteria;

    $criteria->with=array('genres'=>array('select'=>false),

      'from'=>array('select'=>'name'));

    $criteria->group='t.id,from.id'

    //$criteria->limit=-1;

    $criteria->together=true;


    $criteria->compare('t.id',$this->id);

    $criteria->compare('t.name',$this->enabled);

    $criteria->compare('genres.id',$this->hisGenre);

    $criteria->compare('from.name',$this->isFrom);


    return new KeenActiveDataProvider(get_class($this), array(

        'pagination'=>array(

          'pageSize'=> Yii::app()->user->getState('pageSize',Yii::app()->params['defaultPageSize']),

        ),

        'withKeenLoading' => array('genres'),

        'criteria'=>$criteria,

        'sort'=>array('defaultOrder'=>'t.id ASC','attributes'=>array('hisGenre'=>array('asc'=>'COUNT(genres_genres.author_id)','desc'=>'COUNT(genres_genres.author_id) DESC'),'isFrom'=>array('asc'=>'from.name', 'desc'=>'from.name desc'),'*')),

    ));

        }



Then I comment the line giving the primary key in keenloading extension and all works perfectly ;)

Hi

I installed PostgreSql and the Chinook database.

I stumbled on a first issue which was that the column in GROUP BY had to be quoted, I updated KeenDataProvider like this:




            $pkNames = (array)$this->model->tableSchema->primaryKey;

            $schema=$this->model->getDbConnection()->getSchema();

            foreach($pkNames as $k=>$v)

            {

                $pkNames[$k] = $schema->quoteColumnName($this->model->tableAlias.'.'.$v);

            }

            $this->criteria->group = implode(',', $pkNames);



Then I got another issue:


]CDbCommand failed to execute the SQL statement: SQLSTATE[42803]: Grouping error: 7 ERROR: column "track.TrackId" must appear in the GROUP BY clause or be used in an aggregate function

LINE 1: ...UnitPrice" AS "t0_c3", "t"."Quantity" AS "t0_c4", "track"."T...

[size=2]^. The SQL statement executed was: SELECT "t"."InvoiceLineId" AS "t0_c0", "t"."InvoiceId" AS "t0_c1", "t"."TrackId" AS "t0_c2", "t"."UnitPrice" AS "t0_c3", "t"."Quantity" AS "t0_c4", "track"."TrackId" AS "t1_c0", "track"."Name" AS "t1_c1", "track"."AlbumId" AS "t1_c2", "track"."MediaTypeId" AS "t1_c3", "track"."GenreId" AS "t1_c4", "track"."Composer" AS "t1_c5", "track"."Milliseconds" AS "t1_c6", "track"."Bytes" AS "t1_c7", "track"."UnitPrice" AS "t1_c8", "album"."AlbumId" AS "t2_c0", "album"."Title" AS "t2_c1", "album"."ArtistId" AS "t2_c2", "artist"."ArtistId" AS "t3_c0", "artist"."Name" AS "t3_c1" FROM "invoiceline" "t" LEFT OUTER JOIN "track" "track" ON ("track"."TrackId"="t"."TrackId") LEFT OUTER JOIN "album" "album" ON ("album"."AlbumId"="track"."AlbumId") LEFT OUTER JOIN "artist" "artist" ON ("artist"."ArtistId"="album"."ArtistId") GROUP BY "t"."InvoiceLineId" ORDER BY "artist"."Name" DESC,"track"."Name","track"."UnitPrice" DESC LIMIT 4

So I hacked the KeenActiveDataProvider to add these columns to the GROUP BY clause (quick and dirty: explicitally naming them in KeenActiveProvider). That made this request pass, but I then ran into another issue for which I found a workaround.

This is the quick and dirty hack in KeenActiveDataProvider->_prepareKeenLoading().





            $pkNames = (array)$this->model->tableSchema->primaryKey;

            $schema=$this->model->getDbConnection()->getSchema();

            foreach($pkNames as $k=>$v)

            {

                $pkNames[$k] = $schema->quoteColumnName($this->model->tableAlias.'.'.$v);

            }

            $pkNames[]=$schema->quoteColumnName('track.TrackId');    // Explicit column names for test.

            $pkNames[]=$schema->quoteColumnName('album.AlbumId');

            $pkNames[]=$schema->quoteColumnName('artist.Name');

            $this->criteria->group = implode(',', $pkNames);



which got me:


Active record "Invoiceline" is trying to select an invalid column ""t"."InvoiceLineId","track"."TrackId","album"."AlbumId","artist"."Name"". Note, the column must exist in the table or be an expression with alias.

Which is Yii complaining, but I circumvented using another hack in KeenActiveDataProvider->afterFetch().


                    array('select'=>array_merge($this->extrakeys,CPropertyValue::ensureArray(explode(',',$this->criteria->group))),

                          'with'=>$keenGroup)



I still got:


Active record "Invoiceline" is trying to select an invalid column ""album"."AlbumId"". Note, the column must exist in the table or be an expression with alias.

.

Ignoring the exceptin (commenting it) in CActiveFinder, got me past by it, but I got another error entering a search term.

So currently the most effective method is to "disable" keen loading which I do like this in the demo (not uploaded at this moment:


$dataProvider=$model->search();

if($dataProvider instanceof KeenActiveDataProvider) {

   list($type)=explode(':',$model->getDbConnection()->connectionString);

   if($type!=="pgsql") {

    // The keendataprovider does not work well for pgsql

    /* @var $dataProvider KeenActiveDataProvider */

    $dataProvider->withKeenLoading=array(

            'track',

            'track.album',

            'track.album.artist',

            'track.mediatype',

            'invoice.customer',

            'invoice',

            'invoice.customer.support',

            'track.genre',

    );

   }

}



So the issue seems to be with the KeenActiveDataProvider which would have to add the columns to the group by clause. Or maybe there is another that I do not think of at this moment. Skipping it makes the demo work for me on a PostgreSQL database. Some benefit is lost, but there is still a lot of functionnality available in RelatedSearchBehavior…

Hi,

at first I wanna say thanks for this great extension.

I was stuck on problem when you set alias for your model relations definitions but I finally solved it. So I only want to provide you with my experience because someone may consider it useful.

I has got three models


[Category]-1---n-[CategoryLanguage]-n---1-[Language]

Here are my relations definitions fof "Category":




'currentLanguage' => array(self::HAS_ONE, 'CategoryLanguage', 'Category_id', 'alias' => 'ccl', 'with' => array('language:current' => array('joinType' => 'RIGHT OUTER JOIN', 'alias' => 'cl'))),

'languages' => array(self::MANY_MANY, 'Language', 'Category_has_Language(Category_id, Language_id)', 'index' => 'Language_id'),



So category can has only one current language in one moment. As you can see I set alias "ccl" for "currentLanguage" relation.

Here is my relatedsearchbehavior setting for "Category":




'relatedSearchBehavior' => array(

   'class' => 'RelatedSearchBehavior',

   'relations' => array(

      'currentTitle' => 'currentLanguage.title',

      'currentSlug' => 'currentLanguage.slug',

   ),

),



Now you are able to use ‘currentTitle’ and ‘currentSlug’ as column in your CGridView and it will work BUT if you try to sort by one of theese columns following exception appears




Column not found: 1054 Unknown column 'currentLanguage.title' in 'order clause'.



I find out that extensions ignores models relations alias so I modified file "RelatedSearchBehavior.php" by adding following rows on line 179:




...

$shortrelation = substr($shortrelation, $pos + 1);

}




// 13-09-05 - Added by Svobik7

// Fixes relation alias

$ownerRelationsDefinitions = $this->getOwner()->relations();


if (isset($ownerRelationsDefinitions[$shortrelation]))

{

   $currentRelationDefinition = $ownerRelationsDefinitions[$shortrelation];


   if (isset($currentRelationDefinition['alias']))

   {

      $shortrelation = $currentRelationDefinition['alias'];

   }

}

// END - Svobik7's relation alias fix




// The column reference in the query is the table alias + the column name.

$column = "$shortrelation.$column";

...



After that it works great. So I hope it will help someone else to save his/her time.

Hello there, thanks for your extension, it should be the right solution to my problems with the displaying of related fields for my model gridview. Unfortunately I’m stuck with the configuration of the behavior.

My tables:




CREATE TABLE `offerte` (

	`id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT,

	PRIMARY KEY (`id`),

)

CREATE TABLE `offerte_gruppi_accesso` (

	`id` TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT,

	`gruppo_accesso` VARCHAR(50) NOT NULL DEFAULT '0',

	`label` VARCHAR(50) NULL DEFAULT NULL,

	PRIMARY KEY (`id`)

)

CREATE TABLE `offerte_gruppi_accesso_bridge` (

	`id_offerta` SMALLINT(5) UNSIGNED NOT NULL,

	`id_gruppi_accesso` TINYINT(3) UNSIGNED NOT NULL,

	PRIMARY KEY (`id_offerta`, `id_gruppi_accesso`),

	INDEX `FK_offerte_gruppi_accesso` (`id_gruppi_accesso`),

	CONSTRAINT `FK_offerte_offerta` FOREIGN KEY (`id_offerta`) REFERENCES `offerte` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,

	CONSTRAINT `FK_offerte_gruppi_accesso` FOREIGN KEY (`id_gruppi_accesso`) REFERENCES `offerte_gruppi_accesso` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE

)



This is my relations situation inside of the model Offerte, in whose crud I want to be able to filter related fields:




public function relations() {

        return array(

                 'aeGOfferteGruppiAccessos' => array(self::MANY_MANY, 'OfferteGruppiAccesso', '{{offerte_gruppi_accesso_bridge}}(id_offerta, id_gruppi_accesso)'),

             );

    }



The latter means that I have another table ({{offerte_gruppi_accesso_bridge}}) which has the reference to the id of the record inside Offerte (id_offerta) and the reference to another table {{offerte_gruppi_accesso}} which contains records holding the label that will help me with the filter display in the grid.

I did the following

  1. installed the behavior and its dependencies.

  2. added in the model search():


$criteria->compare('offerte_gruppi_accesso.gruppo_accesso', $this->gruppi_accesso, true);

and replaced the model search call to CActiveDataProvider with


return $this->relatedSearch(

    $criteria

);

  1. added the behavior to my model (Offerte):



function behaviors() {

        return array(

            'relatedsearch' => array(

                'class' => 'RelatedSearchBehavior',

                'relations' => array(

                    'gruppi_accesso' => 'aeGOfferteGruppiAccessos.id',

                ),

            ),

        );

    }

  1. added ‘gruppi_accesso’ safe on search rules()

  2. added ‘gruppi_accesso’ in the CGridView as a normal column

When visiting the admin page, I get no errors, but when I try to filter using gruppi_accesso I get an error.

Here is the query that the system tries to execute:


Column not found: 1054 Unknown column 'offerte_gruppi_accesso.gruppo_accesso' in 'where clause'. The SQL statement executed was: SELECT COUNT(DISTINCT `t`.`id`) FROM `offerte` `t` LEFT OUTER JOIN `offerte_gruppi_accesso_bridge` `aeGOfferteGruppiAccessos_aeGOfferteGruppiAccessos` ON (`t`.`id`=`aeGOfferteGruppiAccessos_aeGOfferteGruppiAccessos`.`id_offerta`) LEFT OUTER JOIN `offerte_gruppi_accesso` `aeGOfferteGruppiAccessos` ON (`aeGOfferteGruppiAccessos`.`id`=`aeGOfferteGruppiAccessos_aeGOfferteGruppiAccessos`.`id_gruppi_accesso`) WHERE ((offerte_gruppi_accesso.gruppo_accesso LIKE :ycp0) AND (`aeGOfferteGruppiAccessos`.`id` LIKE :ycp1))

Can anybody point out what am I missing here?

Thanks in advance. :)

You need to write your compare with regards to the relation, not the table:




$criteria->compare('aeGOfferteGruppiAccessos.gruppo_accesso', $this->gruppi_accesso, true);



I notice in your code that you are comparing ‘gruppi’ to ‘gruppo’ (which is not the cause of the exception).

I prefer to do this:




function behaviors() {

	return array(

		'relatedsearch' => array(

			'class' => 'RelatedSearchBehavior',

			'relations' => array(

				'gruppi_accesso' => 'aeGOfferteGruppiAccessos.id',

				'gruppo_accesso' => 'aeGOfferteGruppiAccessos.gruppo_accesso',

			),

		),

	);

}

And add ‘gruppo_accesso’ as a safe attribute.

(The compare is added by the RelatedSearchBehavior).

Actually, it is likely that you get the behavior you expect by removing your ‘compare’ statement.

Hi, thanks for the reply.

I removed the compare statement inside search(), edited the behavior as you suggested, but now I get the error:


Column not found: 1054 Unknown column 'aeGOfferteGruppiAccessos.id' in 'where clause'. The SQL statement executed was: SELECT `t`.`id` AS `t0_c0`, `t`.`offerta` AS `t0_c1`, `t`.`codice_offerta` AS `t0_c2`, `t`.`data_validita_from` AS `t0_c3`, `t`.`data_validita_to` AS `t0_c4`, `t`.`tipologia_id` AS `t0_c5`, `t`.`descrizione` AS `t0_c6`, `t`.`create_at` AS `t0_c7` FROM `ae_g_offerte` `t` WHERE (`aeGOfferteGruppiAccessos`.`id` LIKE :ycp0) LIMIT 10 

Now the query doesn’t have any left join on the referenced tables… I’m kinda lost here :(

I have reproduced the issue after setting up a test case here. I have to check what happens.


<?php


class m141129_170435_db_yiiforum_topic40185_entry268100 extends CDbMigration

{

	public function up()

	{

    	$tb_off='{{offerte}}';

    	$tb_gr='{{offerte_gruppi_accesso}}';

    	$tb_br='{{offerte_gruppi_accesso_bridge}}';


    	$this->createTable($tb_off,

            	array('id'=>'pk')

    	);

    	$this->createTable($tb_gr,

            	array(

                    	'id'=>'pk',

                    	'gruppo_accesso'=>'VARCHAR(50) DEFAULT 0',

                    	'label'=>'VARCHAR(50)',

               )

    	);

    	$this->createTable($tb_br,

            	array(

                    	'id_offerta'=>'INT(5) NOT NULL',

                    	'id_gruppi_accesso'=>'INT(5) NOT NULL',

                    	'PRIMARY KEY( id_offerta,id_gruppi_accesso)',

                    	"FOREIGN KEY(id_offerta) REFERENCES $tb_off(id)",

                    	"FOREIGN KEY(id_gruppi_accesso) REFERENCES $tb_br(id)",

                   )

    	);

    	//$this->createIndex('FK_offerte_gruppi_accesso', $tb_br, 'id_gruppi_accesso');

    	//$this->addForeignKey('FK_offerte_offerta', $tb_br, 'id_offerta', $tb_off,'id','CASCADE','NO ACTION');

    	//$this->addForeignKey('FK_offerte_gruppi_accesso', $tb_br, 'id_gruppi_accesso', $tb_gr,'id','CASCADE','NO ACTION');

	}


	public function down()

	{

    	$this->dropTable('{{offerte}}');

    	$this->dropTable('{{offerte_gruppi_accesso}}');

    	$this->dropTable('{{offerte_gruppi_accesso_bridge}}');

    	return true;

	}


}

Hi

I can’t make the release right now, but you have to uncomment the line (in RelatedSearchBehavior.php)


        $criteria->together=true;

which got commented.

I probably did not see that because I add it in all/most of my searches.

Thank you very much, now the system can filter properly :).

There is still an issue, I guess, related to the relation item (gruppo_accesso) which doesn’t display the value of every record in the grid, even if it filters correctly.

It looks like search() can access related data, while the widget cannot.

The scenario that leads to this problem is: one Offerte object that has two related records inside the _bridge table (many_many with the gruppo_accessi table).

So the row in the grid should be able to display something like "gruppo_accesso_1 - gruppo_accesso_2".

edit:

I guess the problem could be here:




// Not in search scenario - return the normal value.

            if(isset($this->relations[$key])||isset($this->relations[$key=strtolower($key)])) {

                // This field is known in our relations

                $relationvar = $this->relations[$key];

                if(is_array($relationvar)) {

                    // Complex field: has different value for search and display value.

                    if(isset($relationvar['value'])) {

                        $valueField=$relationvar['value'];

                    } else {

                        $valueField=$relationvar['field'];

                    }

                    $value=CHtml::value($this->getOwner(),$valueField);

                } else {

                    // Standard field: same value for searh and for display value.

                    $relationfield=$relationvar;

                    $value=CHtml::value($this->getOwner(),$relationvar);

                }

                return $value;

            }




I’m trying to debug it in the meanwhile.

You can solve that:

  1. By adding an expression in the table the elements;

  2. By doing the search on the join table, instead of Offerte -> you get one line for each combination in the grid.

The ‘search’ accesses the related data because it is part of the Excel search and it will get all the records that correspond to the criteria.

However, once you call on the relation itself, it will fetch all the records according to the condition provided in the relation (independent of the search).