I'm trying to set up a database, the relevant bits of which are shown below. I'm using SQLite3 (3.8.8.3-1) on Arch Linux, with DBIx::Class 0.082820.
It's part of a simple book-keeping system. An invoice line has_one transaction, but a transaction only might_have an corresponding invoice line (because some transactions can be created without an invoice).
I can't get DBIx::Class to insert an invoice line and its corresponding transaction in one go. The error messages are below too.
Am I doing it wrong? Or doing something that doesn't make sense?
And why does it start by searching for an existing transaction with the same description?
Here are the gory details of my much-simplified test case:
InvoiceLine.pm:
package Test::DB::Schema::Result::InvoiceLine;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->table("invoice_lines");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"txn_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0,
is_deferrable => 1 }, # tried this, but it doesn't help
'details',
{ data_type => 'text', is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
# Invoice line has an associated transaction
__PACKAGE__->has_one(
"txn",
"Test::DB::Schema::Result::Transaction",
'id',
);
# Experimental -- this doesn't work either
#__PACKAGE__->belongs_to(
# "txn",
# "Test::DB::Schema::Result::Transaction",
# "txn_id",
#);
1;
Transaction.pm:
use utf8;
package Test::DB::Schema::Result::Transaction;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->table("transactions");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
'description',
{ data_type => 'text', is_nullable => 0 },
# Invoice line
# Null if no associated invoice
'invoice_line_id',
{data_type => 'integer', is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
# Some transactions have a single corresponding
# invoice line
__PACKAGE__->might_have(
"invoice_line",
"Test::DB::Schema::Result::InvoiceLine",
'id',
{ cascade_copy => 0, cascade_delete => 0 },
);
# EXPERIMENTAL == this doesn't work either
# might_have isn't working, so try has_many (where many can be 0):
#__PACKAGE__->has_many(
# 'invoice_lines',
# "Test::DB::Schema::Result::InvoiceLine",
# 'txn_id',
#);
1;
Test.pl
#!/usr/bin/perl
# Test.pl
# Testing might_have <-> has_one relationship
use Test::DB::Schema;
my $schema = Test::DB::Schema->connect(
"dbi:SQLite:dbname=dbic_test.db", '', '', {}
);
$schema->deploy({ add_drop_table => 1 } , '.');
$schema->storage->debug(1);
my $data1 = {
details => 'abc',
txn => {
description => 'xyz',
}
};
my $new1 = $schema->resultset('InvoiceLine')->create($data1);
The result of running Test.pl is:
BEGIN WORK
SELECT me.id, me.description, me.invoice_line_id FROM transactions me WHERE ( me.description = ? ): 'xyz'
INSERT INTO transactions ( description) VALUES ( ? ): 'xyz'
INSERT INTO invoice_lines ( details, id) VALUES ( ?, ? ): 'abc', '1'
DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::SQLite::st execute failed: NOT NULL constraint failed: invoice_lines.txn_id [for Statement "INSERT INTO invoice_lines ( details, id) VALUES ( ?, ? )"] at ./Test.pl line 16
DBIx::Class::Storage::TxnScopeGuard::DESTROY(): A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back. at /usr/share/perl5/site_perl/DBIx/Class/Exception.pm line 77
ROLLBACK