doushu2699 2019-05-07 07:38
浏览 225
已采纳

Yii1 search()由多对多关系返回一个相关模型

I have 3 tables: clients, traders and client_trader_relation

clients can have many traders, and traders can have many clients so this is a MANY-MANY relationship with a "pivot" table. The relation is defined in clients model like this:

$relations = array(
        'traders' => array(self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)'),
);

Now everything works correctly when displaying a listing of all clients in let's say CGridView, but I also want to be able to search for clients by a specific trader (so if one of the traders is let's say id 10, then return this client).

I have done it like this in model's search() function:

public function search()
{
    $criteria=new CDbCriteria;

    $criteria->with = 'traders';
    $criteria->together = true;
    $criteria->compare('traders.id', $this->search_trader);
}

search_trader is an additional variable added to the model & rules so it cna be used for searching. While this works, it successfully returns all clients of specified trader, the result doesn't contain any other related traders, just the one I'm searching for. I can understand this behaviour, because that's the way the generated SQL works.

I'm curious though if there is any way to return all the traders from such search without having to make any additional queries/functions? If not, then what would be the correct way of doing such thing? As for now, I can only think of some function in the model like getAllTraders() that would manually query all the traders related to current client. That would work, I could use this function for displaying the list of traders, but it would produce additional query and additional code.

  • 写回答

1条回答 默认 最新

  • dongza1708 2019-05-07 09:56
    关注

    You can use this to disable eager loading:

    $this->with(['traders' => ['select' => false]]);
    

    But this will create separate query for each row, so with 20 clients in GridView you will get extra 20 queries. AFAIK there is no clean and easy way to do this efficiently. The easiest workaround is to define additional relation which will be used to get unfiltered traders using eager loading:

    public function relations() {
        return [
            'traders' => [self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)'],
            'traders2' => [self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)'],
        ];
    }
    

    And then define with settings for eager loading:

    $this->with([
        'traders' => ['select' => false],
        'traders2',
    ]);
    

    Then you can use $client->traders2 to get full list of traders.


    You can also define this relation ad-hoc instead of in relations():

    $this->getMetaData()->addRelation(
        'traders2',
        [self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)']
    );
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog
  • ¥15 Excel发现不可读取的内容