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

Perl 使用DBIx::Class的多对多访问器,perl,many-to-many,catalyst,dbix-class,Perl,Many To Many,Catalyst,Dbix Class,使用DBIx::Class,我试图创建一个多对多访问器,甚至只是一个跨越两个链接表的has-many关系 讨论中的三个数据表是用户、角色和页面,以及两个链接表UserRoles和RolePages。这些表格相互关联,因此: 一个用户有许多用户角色 一个角色有许多用户角色 一个角色有很多角色 一页有许多角色页 Catalyst helper脚本为我创建了以下关系和访问器: package MyApp::Schema::Result::User; __PACKAGE__->has_many(

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

讨论中的三个数据表是用户、角色和页面,以及两个链接表UserRoles和RolePages。这些表格相互关联,因此:

一个用户有许多用户角色 一个角色有许多用户角色 一个角色有很多角色 一页有许多角色页 Catalyst helper脚本为我创建了以下关系和访问器:

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 Single parameters to new中捕获的异常必须是散列引用

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


是否可以创建跨越两个链接表的访问器/关系?如果是,怎么做?我在文档中找不到一个例子,我自己也没有什么想法了。如果不能做到这一点,我想知道为什么我的pages方法会出现这种错误吗?

据我所知,没有内置的多对多对多关系支持,但要实现自己的关系并不难

在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多对多关系桥接器的功能等价物。

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

在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多对多关系桥的函数等价物。

当RS或undef中只有一个项目时,搜索方法将返回单个对象,而不是结果集,如果没有找到匹配项-如果将其更改为->搜索,问题是否会消失。。。,强制它总是返回结果集?不,不幸的是,我仍然将单个参数设置为new肯定是一个HASH ref错误。不过,最好将其保留为搜索,以确保其返回可预测的数据类型。谢谢。这个错误看起来像是Moose错误,而不是DBIx错误。在某个地方,您使用一个非hashref参数调用new—您确定问题出在DBIx中吗?您是否可以创建一个$user实例并直接调用$user->pages来查看它是否返回您认为的结果?您是对的。异常在/opt/ActivePerl-5.14/site/lib/Moose/Object.pm中提出;在我的根控制器的开始处。它似乎为下面提到的新pages方法和我的旧方法返回了一些合理的结果。但是,在这个语句中使用我的旧方法时会导致错误:$c->user->pages->searchundef,{columns=>['page\u name'],distinct=>1,order\u by=>'sort\u order'}->get_column'page_name'->AllSearch方法将返回单个对象,而不是结果集,如果在RS或undef中只有一个项目,则未找到匹配项-如果将其更改为->search_RS…,强制其始终返回结果集,问题是否会消失?否,不幸的是,我仍然得到new的单个参数必须是HASH-ref错误。不过,最好将其保留为搜索,以确保其返回可预测的数据类型。谢谢。这个错误看起来像是Moose错误,而不是DBIx错误。在某个地方,您使用一个非hashref参数调用new—您确定问题出在DBIx中吗?您是否可以创建一个$user实例并直接调用$user->pages来查看它是否返回您认为的结果?您是对的。异常在/opt/ActivePerl-5.14/site/lib/Moose/Object.pm中提出;在我的根控制器的开始处。它似乎为下面提到的新pages方法和我的旧方法返回了一些合理的结果。但是,在这个语句中使用我的旧方法时会导致错误:$c->user->pages->searchunde,{columns=>['page\u name'],distinct=>1,order\u by=>'sort\u order'}->get\u column'page\u name'->all