[Dbix-class] update_or_insert from hash reference

Fernan Aguero fernan at iib.unsam.edu.ar
Tue May 23 20:34:12 CEST 2006


+----[ Matt S Trout <dbix-class at trout.me.uk> (23.May.2006 13:50):
|
| Fernan Aguero wrote:
| > Hi!
| > 
| > I'm new to DBIx::Class and after setting up a mysql database
| > I'm trying to test DBIx::Class by defining a minimal
| > object-relational mapping for a single table:
| > 
| > TABLE users (
| >   user_id (PK, auto_increment),
| >   username,
| >   firstname,
| >   lastname.
| >   is_allowed_to_edit_database,
| >   date_modified,
| >   date_added )
| > 	
| > What I want to do to populate the DB is something like this:
| > 
| > my $userHashRef = {
| >   username  => $username,
| >   firstname => $firstname,
| >   lastname  => $lastname,
| >   ... ...
| >   };
| > 
| > And then 
| > 
| > # get an object
| > my $appUser = MyApp::DB::User->new( $userHashRef );
| > 
| > # update or insert
| > $appUser->update_or_insert;

[snipped]

| > What am I missing? What am I doing wrong? Thanks in advance,
| 
| Read the Manual - you've not loaded the components you need, your new() 
| method is both unnecessary and broken, and there's no update_or_insert 
| method - you want $rs->update_or_create ...
|
+----]

Matt,

thanks for sending me to RTFM :) 

It's not that I haven't read it ... but some things don't
make sense to me (yet) ... perhaps I haven't fully entered
the ORM or DBIx::Class orbit. 

Now, I have my insertdb test script working (but read
below). I have not changed the loading of components ... so
what do you mean by "you've not loaded the components you
need"?

I got rid of the new() method, my Users.pm now looks like
this:

package MyApp::DB::Users;

use base qw/DBIx::Class/;

__PACKAGE__->load_components( qw/Core PK::Auto/ );

# set the table name
__PACKAGE__->table('users');

# set columns in the table
__PACKAGE__->add_columns( qw/
	user_id username password date_modified date_added firstname
	lastname is_allowed_to_edit_database / );
	
# set the primary key
__PACKAGE__->set_primary_key( qw/ user_id /);

1;


and in my script I use it like this:

my $userHashRef = { 
  user_id   => $user_id,
  username  => $username, 
  firstname => $firstname,
  ... };
  
my $dbix = MyApp::DB->connect( 'dbi:mysql:dbname=... );

my $resultSetObj = $dbix->resultset('Users')->search( $userHashRef );

$resultSetObj->update_or_create;


Now the first time I ran the script, I filled the hash ref
with data for a user but without setting the user_id
(primary key), as this will be automatically generated (and
incremented) by mysql (the same goes for the date columns).

This worked fine and I got the following inserted into the
DB:

user_id username firstname lastname ... is_allowed...
-----------------------------------------------------
1       fernan   Fernn    Aguero   ...  Y

On a second run, I set the user_id to '1' and in the hash
ref I changed the typo in the firstname and changed the
is_allowed_to_edit_database from Y to N.

When running the script I stepped into this:
DBIx::Class::ResultSet::update_or_create(): Error executing
'INSERT INTO users (firstname, ..., user_id, username)
VALUES (?, ?, ...) ('Fernan', ..., '1', 'fernan'):
DBD::mysql::st execute failed: Duplicate entry '1' for key 1
at /usr/local/lib/perl5/site_perl/5.8.8/DBIx/Class/Storage/DBI.pm
line 525.

Why is it trying to INSERT when it should have UPDATED the
row? 

I've read TFM :) and so far the documentation for the
update_or_create method in DBIx::Class::ResultSet confirms
what the method name suggests: that it will first search
"for an existing row matching one of the unique constraints
(including the primary key) on the source of this resultset.
If a row is found, updates it with the other given column
values.  Otherwise, creates a new row."

Will it use the primary key as declared in Users.pm? Or
should I have to pass it as an extra attribute to the search
call? (i.e. as in ->search( hashRef, { key => user_id } ) )
I've already tried this and it didn't work ... but maybe I'm
doing something wrong (again).

Fernan





More information about the Dbix-class mailing list