[Dbix-class] has_many/belongs_to relationship to non-primary key
Matija Grabnar
matija at serverflow.com
Fri Mar 23 14:39:24 GMT 2007
Is this something that database theory makes impossible (and I just
didn't know it) or is this a bug in DBIx::Class?
Summary: Say I have two Classes, in a belongs_to / has_many
relationship, but with one important difference: the belongs_to
relationship does not go to the primary key of the other table, but to
another key. When I try to do that, I get an extra constraint that
prevents me from inserting anything into the table.
package HSL::MailStructure::A;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("PK::Auto", "Core");
__PACKAGE__->table("a");
__PACKAGE__->add_columns(
"i",
{ data_type => "INT", default_value => 0, is_nullable => 0, size => 11 },
"j",
{ data_type => "INT", default_value => 0, is_nullable => 1, size => 11 },
);
__PACKAGE__->set_primary_key("i");
__PACKAGE__->add_unique_constraint("a_j", ["j"]);
__PACKAGE__->has_many(
"bs",
"HSL::MailStructure::B",
{ "foreign.j" => "self.j" },
);
1;
and
package HSL::MailStructure::B;
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components("PK::Auto", "Core");
__PACKAGE__->table("b");
__PACKAGE__->add_columns(
"id",
{ data_type => "INT", default_value => 0, is_nullable => 0, size => 11 },
"j",
{ data_type => "INT", default_value => 0, is_nullable => 1, size => 11 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to("a","HSL::MailStructure::A",
{"foreign.j"=>"self.j"});
1;
It works if table B refers to the primary key of table A, but not if it
refers
to another column:
If the key that class B is tied to is "i" (the primary key of table a),
then sql translator generates a single constraint statement, (in table
b) that looks like this:
CREATE TABLE `b` (
`id` int(11) NOT NULL default '0',
`j` int(11) default '0',
PRIMARY KEY (`id`),
KEY `id` (`id`),
KEY `j` (`j`),
CONSTRAINT `b_fk_j` FOREIGN KEY (`j`) REFERENCES `a` (`i`) ON DELETE
CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
table a is created without foreign key constraints:
CREATE TABLE `a` (
`i` int(11) NOT NULL default '0',
`j` int(11) default '0',
PRIMARY KEY (`i`),
UNIQUE KEY `a_j` (`j`),
KEY `i` (`i`),
KEY `j` (`j`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
However, if class B refers to the non-primary key, then table a gets
an extra foreign key constraint:
CREATE TABLE `a` (
`i` int(11) NOT NULL default '0',
`j` int(11) default '0',
PRIMARY KEY (`i`),
UNIQUE KEY `a_j` (`j`),
KEY `i` (`i`),
KEY `j` (`j`),
CONSTRAINT `a_fk_j` FOREIGN KEY (`j`) REFERENCES `b` (`j`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
That constraint means that it is impossible to insert anything into
table a, since the constraint means it would need to have the
appropriate value already present in b - but you can't insert it in b,
because that has it's own constraint preventing that:
mysql> insert into a values (1,1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key
constraint fails (`hsl/a`, CONSTRAINT `a_fk_j` FOREIGN KEY (`j`)
REFERENCES `b` (`j`))
mysql> insert into b values (1,1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key
constraint fails (`hsl/b`, CONSTRAINT `b_fk_j` FOREIGN KEY (`j`)
REFERENCES `a` (`j`) ON DELETE CASCADE ON UPDATE CASCADE)
Is what I am trying to do impossible due to something in database theory
that I am overlooking (a distinct possibility - if so, please educate
me), or is it a bug in deploy and
SQL::Translator::Producer::DBIx::Class::File?
The reason I need to tie the relationship to the non-primary key is that
it is not the only relationship: there are other relationships tied to
the primary key of the real table I'm having this problem with, this is
just as small a reduction of the problem as I can manage...
Best regards,
Matija Grabnar
More information about the Dbix-class
mailing list