在 DBIx::Class 中使用自连接的组

发布于 2024-09-18 09:51:53 字数 2414 浏览 0 评论 0原文

我试图了解如何使用 DBIx::Class。

如果我想要记录组,以便组本身可以成为组的成员,我可能会创建一个包含以下内容的模式:

CREATE TABLE groups (
       id    INTEGER PRIMARY KEY,
       name  VARCHAR(100)
       );

CREATE TABLE group_groups (
       parent_id         INTEGER REFERENCES groups(id),
       child_id          INTEGER REFERENCES groups(id),
       PRIMARY KEY(parent_id,child_id)
       );

如果我使用 DBIx::Class::Schema::Loader 转储此模式,我会得到以下关系:

Group.pm

__PACKAGE__->has_many(
  "group_groups_children",
  "Schema::Result::GroupGroup",
  { "foreign.child_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->has_many(
  "group_groups_parents",
  "Schema::Result::GroupGroup",
  { "foreign.parent_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

GroupGroup.pm

__PACKAGE__->belongs_to(
  "child",
  "Schema::Result::Group",
  { id => "child_id" },
  {
    is_deferrable => 1,
    join_type     => "LEFT",
    on_delete     => "CASCADE",
    on_update     => "CASCADE",
  },
);

__PACKAGE__->belongs_to(
  "parent",
  "Schema::Result::Group",
  { id => "parent_id" },
  {
    is_deferrable => 1,
    join_type     => "LEFT",
    on_delete     => "CASCADE",
    on_update     => "CASCADE",
  },
);

我认为我需要一个多对多关系桥,其中组表位于两侧,所以我创建了这个:

__PACKAGE__->many_to_many(
    'childgroups' => 'group_groups_children' , 'child');

__PACKAGE__->many_to_many(
    'parents' => 'group_groups_parents' , 'parent');

因为我对关系桥定义的理解是这样的: 'accessor_name' => '相关表中的 has_many 关系的名称','相关表中属于_to 关系的名称'

当我尝试这段代码时:

my $group_rs = $schema->resultset('Group')->search(
        { id => $id }
);
my $group = $group_rs->first;
foreach my $child ($group->childgroups) {
<snip>

设置 DBIC_TRACE 显示 SQL 为:

SELECT child.id, child.name FROM group_groups me 
       JOIN groups child ON child.id = me.child_id  
       WHERE ( me.child_id = ? )

但我认为该行应该看起来更像:

SELECT child.id, child.name FROM group_groups me 
       JOIN groups child ON child.id = me.child_id 
       JOIN groups parent ON parent.parent_id = me.id 
       WHERE ( me.child_id = ? )

如果有人建议如何我误解了多对多关系桥并纠正我的多对多函数定义,我将不胜感激。

I'm trying to understand how to use DBIx::Class.

If I want groups of records such that groups can themselves be members of groups, I might create a schema that includes something like this:

CREATE TABLE groups (
       id    INTEGER PRIMARY KEY,
       name  VARCHAR(100)
       );

CREATE TABLE group_groups (
       parent_id         INTEGER REFERENCES groups(id),
       child_id          INTEGER REFERENCES groups(id),
       PRIMARY KEY(parent_id,child_id)
       );

If I use DBIx::Class::Schema::Loader to dump this schema, I get the following relationships:

Group.pm

__PACKAGE__->has_many(
  "group_groups_children",
  "Schema::Result::GroupGroup",
  { "foreign.child_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->has_many(
  "group_groups_parents",
  "Schema::Result::GroupGroup",
  { "foreign.parent_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

GroupGroup.pm

__PACKAGE__->belongs_to(
  "child",
  "Schema::Result::Group",
  { id => "child_id" },
  {
    is_deferrable => 1,
    join_type     => "LEFT",
    on_delete     => "CASCADE",
    on_update     => "CASCADE",
  },
);

__PACKAGE__->belongs_to(
  "parent",
  "Schema::Result::Group",
  { id => "parent_id" },
  {
    is_deferrable => 1,
    join_type     => "LEFT",
    on_delete     => "CASCADE",
    on_update     => "CASCADE",
  },
);

I think I need a many_to_many relationship bridge where the group table is on both sides, so I created this:

__PACKAGE__->many_to_many(
    'childgroups' => 'group_groups_children' , 'child');

__PACKAGE__->many_to_many(
    'parents' => 'group_groups_parents' , 'parent');

since my understanding of a the relationship bridge definition goes like this: 'accessor_name' => 'name of has_many relation in the related table', 'name of belongs_to relation in the relating table'

When I attempted this code:

my $group_rs = $schema->resultset('Group')->search(
        { id => $id }
);
my $group = $group_rs->first;
foreach my $child ($group->childgroups) {
<snip>

Setting DBIC_TRACE showed the SQL to be:

SELECT child.id, child.name FROM group_groups me 
       JOIN groups child ON child.id = me.child_id  
       WHERE ( me.child_id = ? )

But I think the line should look more like:

SELECT child.id, child.name FROM group_groups me 
       JOIN groups child ON child.id = me.child_id 
       JOIN groups parent ON parent.parent_id = me.id 
       WHERE ( me.child_id = ? )

If someone would suggest how I am misunderstanding the many_to_many relationship bridge and correct my many_to_many function definitions, I would be grateful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

春花秋月 2024-09-25 09:51:53

在 #dix-class 中询问后,ribasushi 帮助我解决了这个问题。显然,DBIC::Schema::Loader 在 Group.pm 中创建了不正确的 has_many 关系,它应该如下所示:

__PACKAGE__->has_many(
  "group_groups_parents",
  "Schema::Result::GroupGroup",
  { "foreign.child_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->has_many(
  "group_groups_children",
  "Schema::Result::GroupGroup",
  { "foreign.parent_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

原文:

has_many (group_groups_children => "Schema::Result::GroupGroup", { "foreign.child_id" => self.id" } )

意思是“在 child_id 中包含我的 id 的所有行”,实际上是父母在他们的 id 中包含我的 id。 child.id,而不是孩子。

我的模式很好,我的关系定义很好,我的使用代码很好,只是自动生成的关系不是很好,而且我的理解不足以发现失败。

ribasushi 暗示命名约束(即我的模式的“更好”DDL)可能导致 DBICSL 得到正确的结果。

Upon asking in #dbix-class, ribasushi helped me resolve this. Apparently, DBIC::Schema::Loader created incorrect has_many relationships in Group.pm and it should look like this:

__PACKAGE__->has_many(
  "group_groups_parents",
  "Schema::Result::GroupGroup",
  { "foreign.child_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

__PACKAGE__->has_many(
  "group_groups_children",
  "Schema::Result::GroupGroup",
  { "foreign.parent_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

The original:

has_many (group_groups_children => "Schema::Result::GroupGroup", { "foreign.child_id" => self.id" } )

means "all the rows that have my id in child_id" and really it's the parents that have my id in their child.id, not the children.

My schema was good, my relationship definitions were good, my usage code was good, it was just that the autogenerated relationships were not and my understanding was not sufficient to discover the failing.

ribasushi hinted that named constraints (i.e "better" DDL for my schema might have resulted in DBICSL getting it right.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文