使用DBIx :: Class预取相关行或不行,可能使用OUTER LEFT JOIN?

Dan*_*mer 6 sql perl join dbix-class

我想从表中检索行,DBIx::Class并从同一个表中预取相应的行,其中列具有特定的其他值.我需要从计划A中获取所有作业(复制它们)并从计划B中检索所有相应的作业.

我已经编制了测试表,看起来像这样:

CREATE TABLE tasks (
    id INTEGER
);

CREATE TABLE schedules (
    id INTEGER
);

CREATE TABLE assignments (
    id INTEGER,
    scheduleId INTEGER,
    taskId INTEGER,
    worker TEXT,
    FOREIGN KEY (scheduleId) REFERENCES schedules(id),
    FOREIGN KEY (taskId) REFERENCES tasks(id)
);
Run Code Online (Sandbox Code Playgroud)

计划1有一些任务,计划2有一些任务:

INSERT INTO tasks (id) VALUES (1);
INSERT INTO tasks (id) VALUES (2);
INSERT INTO schedules (id) VALUES (1);
INSERT INTO schedules (id) VALUES (2);
INSERT INTO assignments (id,scheduleId,taskId,worker) VALUES (1,1,1,"Alice");
INSERT INTO assignments (id,scheduleId,taskId,worker) VALUES (2,1,2,"Bob");
INSERT INTO assignments (id,scheduleId,taskId,worker) VALUES (3,2,1,"Charly");
Run Code Online (Sandbox Code Playgroud)

这是一些返回所需结果的SQL:

SELECT * FROM assignments AS a1
LEFT OUTER JOIN assignments AS a2 ON
    a2.scheduleId = 2 AND
    a2.taskId = a1.taskId
WHERE a1.scheduleId = 1;
Run Code Online (Sandbox Code Playgroud)

在SQLite中,这可以按预期工作:结果显示了来自计划1的每个分配和来自计划2的相应分配的一行.

id|scheduleId|taskId|worker|id|scheduleId|taskId|worker
1|1|1|Alice|3|2|1|Charly
1|1|2|Bob|NULL|NULL|NULL|NULL
Run Code Online (Sandbox Code Playgroud)

到目前为止,我尝试使用DBIx :: Class不起作用.这是作业的类看起来像:

package MyApp::Schema::Result::Assignment;

...

__PACKAGE__->has_many(
    inAllSchedules => 'MyApp::Schema::Result::Assignment',
    {
        'foreign.taskId' => 'self.taskId',
    }
);
Run Code Online (Sandbox Code Playgroud)

以下代码正确连接行但仅返回计划1中的行,这些行实际上具有计划2中的相应行:

my $assignments = $schema->resultset('Assignment')->search({
    'inAllSchedules.scheduleId' => 2,
}, {
    prefetch => 'inAllSchedules',
});
Run Code Online (Sandbox Code Playgroud)

此代码也正确地correclty连接行并返回没有连接行的行,但我不知道如何过滤连接的行.我不想检索计划3等行或任何其他行......

my $assignments = $schema->resultset('Assignment')->search(undef, {
    join_type => 'left outer',
    prefetch => 'inAllSchedules',
});
Run Code Online (Sandbox Code Playgroud)

我无法编写特定的关系,因为时间表A或B的ID仅在运行时给出.

如何生成给定的SQL代码或以其他方式检索数据?

AKH*_*and 3

这看起来像是自定义连接条件的情况。下面的解决方案适用于您有限的示例,但可能需要针对您的实际应用程序进行调整。

__PACKAGE__->has_many(
    'inAllSchedules' => "MyApp::Schema::Result::Assignment",
    sub {
        my $args = shift;

        return {
            "$args->{foreign_alias}.taskId" => { '-ident' => "$args->{self_alias}.taskId" },
            "$args->{foreign_alias}.id" => { '<>' => { '-ident' => "$args->{self_alias}.id" } },
        };
    }
);
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它:

my $assignments = $schema->resultset("Assignment")->search({
    'me.scheduleId'             => 1,
    'inAllSchedules.scheduleId' => [ 2, undef ],
},
{
   'prefetch' => "inAllSchedules",
});
Run Code Online (Sandbox Code Playgroud)