[Dbix-class] problem with many to many relashionship.

Ferruccio Zamuner nonsolosoft at diff.org
Wed Apr 11 21:58:41 GMT 2007


Hello,

I was trying to display a page with a report about users, their roles and so on.

my @users = $c->model('FlipperDB::Users')->search({},{prefetch=>{'user_roles'=>'role_id'},order_by=>'last_name'});
my @roles = $c->model('FlipperDB::Roles')->search({},{order_by=>'id'});
foreach my $usr (@users) {
    $form->field(name=>'roles_'.$usr->id, 
                 options=>[ map { [ $_->id, $_->role ] } @roles], 
                 value=>[ map { $_->id } $usr->roles], multiple=>1);
}

But this makes a query for each user to find its roles:

   705:SELECT me.id, me.username, me.password, me.email_address, me.first_name, me.last_name, me.active, me.level, user_roles.user_id, user_roles.role_id, role_id.id, role_id.ro\
le FROM users me LEFT JOIN user_roles user_roles ON ( user_roles.user_id = me.id )  JOIN roles role_id ON ( role_id.id = user_roles.role_id ) ORDER BY last_name, user_roles.user_\
id:
   706:SELECT me.id, me.role FROM roles me ORDER BY id:
   737:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '4'
   753:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '4'
   799:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '2'
   815:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '2'
   861:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '3'
   877:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '3'
   923:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '5'
   939:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '5'
   985:SELECT role_id.id, role_id.role FROM user_roles me  JOIN roles role_id ON ( role_id.id = me.role_id ) WHERE ( me.user_id = ? ): '1'

The Users.pm is like as the Catalyst tutorial, I've only added one line:

__PACKAGE__->many_to_many('roles' => 'user_roles', 'role_id');



I've shown this on IRC dbix-class support group and castaway has helped me:

The modified version:

foreach my $usr (@users) {
    $form->field(name=>'roles_'.$usr->id, 
                 options=>[ map { [ $_->id, $_->role ] } @roles], 
                 value=>[ map { $_->role_id->id } $usr->user_roles], multiple=>1);
}

generates following queries list:

   237:SELECT me.id, me.username, me.password, me.email_address, me.first_name, me.last_name, me.active, me.level, user_roles.user_id, user_roles.role_id, role_id.id, role_id.ro\
le FROM users me LEFT JOIN user_roles user_roles ON ( user_roles.user_id = me.id )  JOIN roles role_id ON ( role_id.id = user_roles.role_id ) ORDER BY last_name, user_roles.user_\
id:
   238:SELECT me.id, me.role FROM roles me ORDER BY id:


just those queries wanted.

The $user->roles() is used by Catalyst::Plugin::Authorization::Roles and ACL and I see a lot time the same query like:

  10:SELECT me.role FROM roles me LEFT JOIN user_roles user_roles ON ( user_roles.role_id = me.id ) WHERE ( me.role IN ( ? ) AND user_roles.user_id = ? ): 'admin', '1'
 110:SELECT me.role FROM roles me LEFT JOIN user_roles user_roles ON ( user_roles.role_id = me.id ) WHERE ( me.role IN ( ? ) AND user_roles.user_id = ? ): 'admin', '1'
1350:SELECT me.role FROM roles me LEFT JOIN user_roles user_roles ON ( user_roles.role_id = me.id ) WHERE ( me.role IN ( ? ) AND user_roles.user_id = ? ): 'admin', '1'

It's normal that each time the authorization is checked on the same request for the same user, it fires query to the db?

Castaway suggested to write down this report and I thank you castaway again.


Bye,               \fer





More information about the Dbix-class mailing list