使用DBIx :: Class的多对多访问器

时间:2012-07-05 17:36:09

标签: perl many-to-many catalyst dbix-class

使用DBIx :: Class,我试图创建一个跨越两个链接表的多对多访问器(甚至只是一个有多个关系)。

有问题的三个数据表是用户角色页面,其中包含两个链接表 UserRoles RolePages 。因此这些表是相关的:

  • 用户有许多 UserRoles
  • 角色有多个 UserRoles
  • 角色有多个 RolePages
  • Page 有许多 RolePages

Catalyst助手脚本为我创建了这些关系和访问器:

package MyApp::Schema::Result::User;

__PACKAGE__->has_many(
  "user_roles",
  "MyApp::Schema::Result::UserRole",
  { "foreign.username" => "self.username" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->many_to_many("roles", "user_roles", "role");


package MyApp::Schema::Result::Role;

__PACKAGE__->has_many(
  "role_pages",
  "MyApp::Schema::Result::RolePage",
  { "foreign.role" => "self.role" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->has_many(
  "user_roles",
  "MyApp::Schema::Result::UserRole",
  { "foreign.role" => "self.role" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->many_to_many("page_names", "role_pages", "page_name")

__PACKAGE__->many_to_many("usernames", "user_roles", "username");


package MyApp::Schema::Result::Page;

__PACKAGE__->has_many(
  "role_pages",
  "MyApp::Schema::Result::RolePage",
  { "foreign.page_name" => "self.page_name" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->many_to_many("roles", "role_pages", "role");


package MyApp::Schema::Result::UserRole;

__PACKAGE__->belongs_to(
  "role",
  "MyApp::Schema::Result::Role",
  { role => "role" },
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);

__PACKAGE__->belongs_to(
  "username",
  "MyApp::Schema::Result::User",
  { username => "username" },
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);


package MyApp::Schema::Result::RolePage;

__PACKAGE__->belongs_to(
  "page_name",
  "MyApp::Schema::Result::Page",
  { page_name => "page_name" },
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);

__PACKAGE__->belongs_to(
  "role",
  "MyApp::Schema::Result::Role",
  { role => "role" },
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);

我的最终目标是获得一个干净的方法来获取应该为当前用户显示的页面列表。即:

foreach my $page ($c->user->pages) {
    # do something with $page
}

我在MyApp :: Schema :: Result :: User类中确实有这个方法:

sub pages {
    my ($self) = @_;

    return $self->result_source->schema->resultset('RolePage')->search(
        {
            'username.username' => $self->username,
        },
        {
            join => [
                {
                    role => {user_roles => 'username'},
                },
                'page_name',
            ],
        }
    );
}

直到我添加了一个类来扩展MyApp :: Schema :: Result :: RolePage。那课从这样开始:

package MyApp::Schema::ResultSet::RolePage;

use Moose;
use namespace::autoclean;
extends qw/MyApp::Schema::ResultSetX::DisplayTable/;

has '+name' => ( default => 'RolePage' );

我在我的应用程序中使用了这种技术,创建了各种结果集,现在只是遇到了麻烦。我收到这个错误:

  

Lifeway :: Controller :: Root-> auto中的捕获异常“new()的单个参数必须是HASH ref

由我的MyApp::Schema::Result::User->pages()方法引起。所以,为了避免这个错误,我想我会尝试从用户页面创建一个多对多访问者(甚至只是一个多人关系)

是否可以创建跨越两个链接表的访问者/关系?如果是这样,怎么样?我在文档中找不到一个例子,并且自己已经用完了想法。如果没有,那么为什么我用pages()方法得到错误的任何想法?

1 个答案:

答案 0 :(得分:4)

据我所知,没有对多对多关系的内置支持,但推出自己的关系并不难。

在Schema :: Result :: User.pm

sub pages {
  my $self = shift;
  return $self->search_related('user_roles')
    ->search_related('role')
    ->search_related('role_pages')
    ->search_related('page_name');
    # Alternatively, if you need to eliminate duplicates:
    # ->search_related('page_name', {}, {distinct => 1});
}

我认为这非常接近于标准DBIx多对多关系桥的功能。

相关问题