加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl – 如何在DBIx :: Class中定义和使用many_to_many关系?

发布时间:2020-12-16 06:21:19 所属栏目:大数据 来源:网络整理
导读:我在DB中有3个表,简化为: book book_language language===== - ============== - ========bookID book_languageID languageIDtitle bookID language languageID 使用DBIx :: Class :: Schema :: Loader我生成了schema,其中有相应的Result类: BookBookLangu
我在DB中有3个表,简化为:

book        book_language       language
=====  <->> ============== <<-> ========
bookID      book_languageID     languageID
title       bookID              language
            languageID

使用DBIx :: Class :: Schema :: Loader我生成了schema,其中有相应的Result类:

Book
BookLanguage
Language

由于某些原因,Loader没有检测到这些表之间的many_to_many关系,所以我在Language类中自己定义了这样的关系:

package R::RMT::Result::Language;
...
__PACKAGE__->many_to_many('books' => 'book_language_rel','bookid_rel');

在Book类中:

package R::RMT::Result::Book;
...
__PACKAGE__->many_to_many('languages' => 'book_language_rel','languageid_rel');

现在我希望能够访问所有相关语言:

my $dsn = "DBI:mysql:database=rkBook";
my $schema = R::RMT->connect( $dsn,'user','pwd' );

my $book_rs = $schema->resultset('Book');
say $book_rs->languages();

但是我得到了错误:

Can't locate object method "languages" via package "DBIx::Class::ResultSet" at ...

我错了什么?我试着把文件中的碎片联系在一起,但显然我弄错了.我从未见过一个关于多少关系应该如何工作的完整例子.

AFAIU,在Result类中定义关系应该在这个类中创建一个访问器.我怎么能看到所有经过处理的存取器?如果我尝试使用Data :: Printer转储ResultSet对象,我只看到列的访问器,但没有关系的访问器.

如果我尝试列表关系:

say $schema->source('Book')->relationships;

我在这里看不到many_to_many关系(也不是那些由DBIx :: Class :: Schema :: Loader拾取的关系),只有has_manys和belongs_tos.

编辑.添加最简单的测试用例:

创建表并填充数据

CREATE TABLE `book` (
  `bookID` int(10) unsigned NOT NULL AUTO_INCREMENT,`title` varchar(255) COLLATE utf8_estonian_ci NOT NULL DEFAULT '',PRIMARY KEY (`bookID`),KEY `title` (`title`)
) ENGINE=InnoDB;

CREATE TABLE `language` (
  `languageID` int(10) unsigned NOT NULL AUTO_INCREMENT,`language` varchar(255) COLLATE utf8_estonian_ci NOT NULL DEFAULT '',PRIMARY KEY (`languageID`),KEY `language` (`language`)
) ENGINE=InnoDB;

CREATE TABLE `book_language` (
  `book_languageID` int(10) unsigned NOT NULL AUTO_INCREMENT,`bookID` int(10) unsigned DEFAULT NULL,`languageID` int(10) unsigned DEFAULT NULL,PRIMARY KEY (`book_languageID`),UNIQUE KEY `book_language` (`bookID`,`languageID`),CONSTRAINT `book_language_ibfk_1` FOREIGN KEY (`languageID`) REFERENCES `language` (`languageID`) ON DELETE SET NULL,CONSTRAINT `book_language_ibfk_2` FOREIGN KEY (`bookID`) REFERENCES `book` (`bookID`) ON DELETE SET NULL
) ENGINE=InnoDB;

INSERT INTO language (language) VALUES ('estonian'),('english'),('polish');
INSERT INTO book (title) VALUES ('Eesti rahva ennemuistsed jutud'),('Estonska-polska slovar'),('21 facts about...'),('Englis-Polish Dictionary');
INSERT INTO book_language (bookID,languageID) VALUES (1,1),(2,3),(3,2),(4,3);

使用默认值生成架构:

dbicdump -o dump_directory=./lib -o debug=1 My::Schema 'dbi:mysql:dbname=testbook' user password

在Book.pm中添加了many_to_many-definitions

# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-21 18:49:05
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ipamXRkSe+HLXGdTGwzQ9w
__PACKAGE__->many_to_many('languages' => 'book_languages','languageid');

在Language.pm中

# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-03-21 18:49:05
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:nZyaWdriRpgEWDAcO3+CFw
__PACKAGE__->many_to_many('books' => 'book_languages','bookid');

运行此脚本:

#!/usr/bin/env perl

use strict; use warnings; use 5.014; use utf8::all;
use My::Schema;

my $dsn = "DBI:mysql:database=testbook";
my $schema = My::Schema->connect( $dsn,'password' );

my $book_rs = $schema->resultset('Book');
say $book_rs->languages();

解决方法

首先请注意,many_to_many只生成辅助方法(访问器),但在连接和预取参数中不能使用它们的意义上不是“真实”关系.

示例代码的问题在于您尝试在结果集对象上调用结果方法(生成的“语言”).

例如,调用$rs-> first->语言将起作用.

如果你想要$book_rs中所有书籍的所有语言,你必须在形成many_to_many的两个关系上使用search_related.如果您预先获取两个数据库或者之前没有获取rs,则不会命中数据库,在这种情况下构建并执行优化查询.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读