srchulo
srchulo

Reputation: 5203

DBIx::Class insert has many

I'm using DBIx::Class and I have two Schemas:

use utf8;
package MyApp::Schema::Result::Person;

use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';

__PACKAGE__->table("person");

__PACKAGE__->add_columns(
    "id",
     { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
);

__PACKAGE__->has_many(
    "addresses",
    "MyApp::Schema::Result::Address",
    { "foreign.person_id" => "self.id" },
    { cascade_copy => 0, cascade_delete => 0 },
);

1;

And:

use utf8;
package MyApp::Schema::Result::Address;

use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';

__PACKAGE__->table("address");

__PACKAGE__->add_columns(
    "id",
     { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
     "person_id",
     { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
);

__PACKAGE__->belongs_to(
    "person",
     "MyApp::Schema::Result::Person",
     { id => "person_id" },
     {  
         is_deferrable => 0,
         join_type     => "LEFT",
         on_delete     => "NO ACTION",
         on_update     => "NO ACTION",
     },  
);

1;

What I am trying to do is add multiple addresses at once with a person object. I am doing that like so:

my $person = $c->model('DB::Person')->new_result({});
$person->addresses([
    {
        id => 1,
        person_id => 1,
    },
    {
        id => 2,
        person_id => 1,
    },
]);

$person->insert;

I followed this format from this article, but it doesn't seem to work. Only the person row gets inserted, but the addresses associated with it do not. I've also tried setting addresses to an arrayref of MyApp::Schema::Result::Address objects before inserting, but that doesn't work either. Does anyone know what I'm doing wrong? I don't get any errors, it just doesn't insert the addresses. In the article they use create instead of insert. Is it because of this? If so, is there a way to do this using insert or update?

Upvotes: 3

Views: 425

Answers (3)

user3947189
user3947189

Reputation:

When you are adding related child records you don't need to specify the value of the foreign key for the children. The relationship should take care of this for you automatically. e.g. in your example person_id is unnecessary.

I suspect this may be causing an issue in the example. How do you know the person_id is really 1? It's an autoincrement column, and you're not explicitly passing in a value when you create the Person.

What happens with this:

-- In Person.pm --

__PACKAGE__->add_columns(
    "id",
     { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
    "name",
     { data_type => "varchar"},
);

-- In Address.pm --

__PACKAGE__->add_columns(
    "id",
     { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
     "person_id",
     { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
    "street",
     { data_type => "varchar"},

);

Then this insert code:

my $person = $c->model('DB::Person')->new_result({ name => "Bob" });
$person->addresses([
    {
        street => "Apple Street",
    },
    {
        street => "Orange Avenue",
    },
]);

$person->insert;

Upvotes: 2

Borodin
Borodin

Reputation: 126732

I would have thought your belongs_to relationship in Address should look like

{ 'foreign.id' => 'self.person_id' }

because id is ambiguous without specifying a table name.

You seem to have it right in the has_many relationship for your Person

Upvotes: 1

Alexander Hartmaier
Alexander Hartmaier

Reputation: 2204

I'm pretty sure that it has to do with the Person object only created in memory, try using create instead.

Is there a reason you want to insert it after having assigned the addresses?

Note that you have two DBIx::Class::Result classes in one DBIx::Class::Schema.

You also should not override auto-increment column values as your database won't know that those ids are already used and try to do so later leading to a hard to track down error.

Upvotes: 0

Related Questions