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

I have a DBIx::Class::Schema built by DBIx::Class::Schema::Loader, and I'm starting to play around with it.

I have a table with a default value for a column (this is an example, not real data):

CREATE TABLE t ( i int DEFAULT 3 NOT NULL, x varchar(255) );

My class knows about this.

__PACKAGE__->load_components( 'PK::Auto', 'Core' ); __PACKAGE__->table('t'); __PACKAGE__->add_columns( 'i', { data_type => 'integer', default_value => 3, is_nullable => 0, size => 4, }, 'x', { data_type => 'character varying', default_value => undef, is_nullable => 1, size => 255, }, );

However, according to DBIx::Class::ResultSource, the default_value is only used by "deploy" in DBIx::Class::Schema. Fine.

The behavior I'm seeing is that if I create a new row, it doesn't have the default value.

my $rs = $schema->resultset( 'T' ); isa_ok( $rs, 'DBIx::Class::ResultSet' ); my $row = $rs->create( { x => 'foo' } ); isa_ok( $row, 'DBIx::Class::Row' ); ok( $row->in_storage(), 'new row is in storage' ); # THIS IS THE TEST THAT FAILS is( $row->i(), 3, 'new row has default value' );

I've done a few laps around the documentation and not found how to handle this.

Ideally, it would know that the data it has doesn't match what's actually in storage. I'd like it to automatically go back to the database and see what's there.

Since I know I left a value to its default, I could undef $row and make a new one with a search for the record I just created. I was hoping, however, that there's a way I could tell the $row, "you're not current". This would be useful also in a case where I might modify something directly with SQL without using the DBIx::Class-based model. Is there such a thing?

Replies are listed 'Best First'.
Re: Default column values in DBIx::Class
by jasonk (Parson) on Jan 12, 2008 at 03:29 UTC

    To tell the object "you're not current" and have it reloaded from the database:

    $row->discard_changes;

    To set the default value from your DBIx::Class object instead of from the database, and avoid the whole problem...

    package MyDB::T; use base qw( DBIx::Class ); # setup stuff ... sub new { my ( $class, $attrs ) = @_; $attrs->{ 'i' } = 3 unless defined $attrs->{ 'i' }; return $class->next::method( $attrs ); }

    We're not surrounded, we're in a target-rich environment!

      Thank you!!

      So as not to have my constants in two places, I've written something like this:

      sub new { my ( $class, $attr ) = @_; foreach my $col ( $class->columns ) { my $col_info = $class->column_info( $col ); if ( ! defined $attr->{$col} && exists $col_info->{default_value} && ! $col_info->{is_auto_increment} ) { $attr->{$col} = $col_info->{default_value}; } } return $class->next::method( $attr ); }

      With the little testing that I've done so far, this seems to work like a charm.

      Thanks again!