Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Using DBIx::Class To Delete Row With Foreign Keys

by varanasi (Scribe)
on Jan 24, 2019 at 15:46 UTC ( [id://1228927]=perlquestion: print w/replies, xml ) Need Help??

varanasi has asked for the wisdom of the Perl Monks concerning the following question:

Using DBIx::Class, I would like to delete a row from a table that contains a field referencing a foreign key. When I try, get this error message (via Catalyst):

DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::SQLite: +:st execute failed: FOREIGN KEY constraint failed [for Statement "DEL +ETE FROM member WHERE ( id = ? )" with ParamValues: 1=6] at /home/mar +k/80-004 Test/script/../lib/Test/Controller/Member/Manage.pm line 91

Would you be kind enough to help me? This problem has harassed me before. Normally, I simply delete away, and life is fine. I don't really know what I'm doing and just trust DBIx::Class to take care of me. Most of the time, it does. Then, the problem pops up, and I mangle things until I get something to work. I've looked at code that works and compared it to code that doesn't, and I'm too inexperienced to see a difference. The time has come for me to finally figure out what is going on.

Specifically, I would like to delete a row from table Member that references a row in table User. I don't wish to touch the row in User. Here's the line I'm using to do the delete:

my $member_obj = $c->model('DB::Member')->find({ id => $member_id }); $member_obj->delete;

Here are the relevant part of my Schema and database sql files (slimmed down):

package Test::Schema::Result::Member; . . . __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0}, "user_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, __PACKAGE__->belongs_to( "user", "Test::Schema::Result::User", { id => "user_id" }, { is_deferrable => 0, join_type => "LEFT", on_delete => "NO ACTION", on_update => "NO ACTION", }, );
package Test::Schema::Result::User; . . . __PACKAGE__->has_many( "members", "Test::Schema::Result::Member", { "foreign.user_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, );
CREATE TABLE member ( id INTEGER PRIMARY KEY, user_id INTEGER REFERENCES user(id) ); CREATE TABLE user ( id INTEGER PRIMARY KEY, username TEXT );

2019-01-25 Athanasius fixed first code block (line was too wide)

Replies are listed 'Best First'.
Re: Using DBIx::Class To Delete Row With Foreign Keys
by 1nickt (Canon) on Jan 24, 2019 at 16:35 UTC

    Hi, I would allow DBIx::Class to manage the relationships, i.e. try removing 'REFERENCES user(id)' from your table schema. It's creating a database foreign key which is preventing the deletion, and as the doc says,

    By default, DBIx::Class cascades deletes across has_many, has_one and might_have relationships. You can disable this behaviour on a per-relationship basis by supplying cascade_delete => 0 in the relationship attributes.

    The cascaded operations are performed after the requested delete, so if your database has a constraint on the relationship, it will have deleted/updated the related records or raised an exception before DBIx::Class gets to perform the cascaded operation.

    Hope this helps!


    The way forward always starts with a minimal test.

      Thanks. Likely I don't understand how cascades work. I thought using a cascade would delete my row in User if I delete the Member row that uses that key.

Re: Using DBIx::Class To Delete Row With Foreign Keys
by poj (Abbot) on Jan 24, 2019 at 16:26 UTC

    Are there any other tables which use member.user_id and have constraints ?

    poj

      Yes! There is one table, Roster, that does:

      package Test::Schema::Result::Roster; . . . __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0}, "member_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, ); . . . __PACKAGE__->belongs_to( "member", "Test::Schema::Result::Member", { id => "member_id" }, { is_deferrable => 0, join_type => "LEFT", on_delete => "NO ACTION", on_update => "NO ACTION", }, ); ------------sql------ CREATE TABLE roster ( id INTEGER PRIMARY KEY, member_id INTEGER REFERENCES member(id) );

        In that case, delete the roster records before deleting the member.

        poj

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1228927]
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2024-04-25 16:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found