DBIx :: Class - 在子表中创建唯一的行

时间:2015-04-13 16:20:02

标签: sql perl dbix-class

我的(简化)SQLite表是这样的:

create table customers (
    id              integer primary key autoincrement,
    contact_name    text,
    billaddr_id     integer references addresses(id)
);

create table addresses (
    id              integer primary key autoincrement,
    address         text
);

以下是结果类(由dbicdump从sql生成):

Test::DB::Schema::Result::Customer->table("customers");
Test::DB::Schema::Result::Customer->add_columns(
    "id", 
    { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
    "contact_name", 
    { data_type => "text", is_nullable => 1 },
    "billaddr_id", 
    { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
);
Test::DB::Schema::Result::Customer->set_primary_key("id");
Test::DB::Schema::Result::Address->table("addresses");
Test::DB::Schema::Result::Address->add_columns(
    "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
    "address", { data_type => "text", is_nullable => 1 },
);
Test::DB::Schema::Result::Address->set_primary_key("id");
Test::DB::Schema::Result::Address->has_many(
    "customers", 
    "Test::DB::Schema::Result::Customer",
    { "foreign.billaddr_id" => "self.id" },
    { cascade_copy => 0, cascade_delete => 0 },
);
Test::DB::Schema::Result::Customer->belongs_to(
    "billaddr",
    "Test::DB::Schema::Result::Address",
    { id => "billaddr_id" },
    {
        is_deferrable => 0,
        join_type     => "LEFT",
        on_delete     => "NO ACTION",
        on_update     => "NO ACTION",
    },
);

这段代码:

my $data = { 
    contact_name => 'Jim Customer',
    billaddr => {
        address => 'Address...',
    },  
};  
my $newcustomer = $c->schema->resultset('Customer')->create($data);

导致此数据库更新:

SELECT me.id, me.address FROM addresses me WHERE ( ( me.address = ? ) ): 'Address...'
BEGIN WORK
SELECT me.id, me.address FROM addresses me WHERE ( ( me.address = ? ) ): 'Address...'
INSERT INTO addresses ( address ) VALUES ( ? ): 'Address...'
INSERT INTO partners ( billaddr_id, contact_name ) VALUES ( ?, ? ) : '10', 'Jim Customer'
COMMIT

为什么在插入之前进行选择?因为它正在检查是否已存在具有相同“地址”列值的地址。如果确实存在,则重复使用该地址的ID,如下所示:

SELECT me.id, me.address FROM addresses me WHERE ( ( me.address = ? ) ): 'Address...'
INSERT INTO partners ( billaddr_id, contact_name ) VALUES ( ?, ? ): '10', 'Another Customer with the same address'

但那不是我想要的!我希望为不同的客户提供单独的地址,即使他们恰好住在同一个地方。

如何使DBIx :: Class每次在地址表中创建一个新行?

1 个答案:

答案 0 :(得分:0)

感谢abraxxa的评论,我指出了正确的方向,并使用DBIx :: Class:Schema进行了更多的阅读和测试。

从Schema类生成表,而不是相反,似乎是要走的路,特别是如果它将来更容易升级到数据库。

我已将问题归结为以下示例代码:

Test.pl:

#!/usr/bin/perl
use Test::DB::Schema;
my $schema = Test::DB::Schema->connect(
    "dbi:SQLite:dbname=dbicsl_test.db", '', '', {}
);
$schema->deploy({ add_drop_table => 1 } , '.');
$schema->storage->debug(1);
my $data1 = { 
    text => 'Fred',
    table2 => {
        text => 'abc',
    }   
};
my $new1 = $schema->resultset('Table1')->create($data1);
my $data2 = { 
    text => 'Jim',
    table2 => {
        text => 'xyz',
    }   
};
my $new2 = $schema->resultset('Table1')->create($data2);
my $data3 = { 
    text => 'Emily',
    table2 => {
        text => 'abc',
    }   
};
my $new3 = $schema->resultset('Table1')->create($data3);

测试:: DB ::架构::结果:: Table1.pm:

package Test::DB::Schema::Result::Table1;
use base 'DBIx::Class::Core';
__PACKAGE__->table("table1");
__PACKAGE__->add_columns(
  "id",
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "text",
  { data_type => "text", is_nullable => 1 },
  "table2_id",
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->has_one(
    table2 =>
    "Test::DB::Schema::Result::Table2",
    { 'foreign.id' => 'self.table2_id' },
);
1;

测试:: DB ::架构::结果::表2:

package Test::DB::Schema::Result::Table2;
use base 'DBIx::Class::Core';
__PACKAGE__->table("table2");
__PACKAGE__->add_columns(
  "id",
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "text",
  { data_type => "text", is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
1;

这是输出:

SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'abc'
BEGIN WORK
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'abc'
INSERT INTO table2 ( text) VALUES ( ? ): 'abc'
INSERT INTO table1 ( table2_id, text) VALUES ( ?, ? ): '1', 'Fred'
COMMIT
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'xyz'
BEGIN WORK
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'xyz'
INSERT INTO table2 ( text) VALUES ( ? ): 'xyz'
INSERT INTO table1 ( table2_id, text) VALUES ( ?, ? ): '2', 'Jim'
COMMIT
SELECT me.id, me.text FROM table2 me WHERE ( me.text = ? ): 'abc'
INSERT INTO table1 ( table2_id, text) VALUES ( ?, ? ): '1', 'Emily'

所以数据库现在看起来像

table1.id  table1.text table1.table2_id
1          Fred        1
2          Jim         2
3          Emily       1

table2.id  table2.text
1          abc
2          xyz

而我期望/希望:

table1.id  table1.text table1.table2_id
1          Fred        1
2          Jim         2
3          Emily       3

table2.id  table2.text
1          abc
2          xyz
3          abc

为什么当我没有告诉它使table2.text列唯一时,它会重用1 / abc?

相关问题