JSON 数据和 DBIx::Class - 如何直接存储数据?
JSON data and DBIx::Class - how can I store data directly?
我有一个带有 JSON 列的 Postgres 数据库,我想为此做这样的事情:
use lib './lib';
use Digest::MD5 qw(md5 md5_hex);
use Data::Dump qw/dump/;
use Foo; # isa 'DBIx::Class::Schema';
$f = Foo->connect('dbi:Pg:database=mydb');
my $i = $f->resultset('People')->create({ id => md5_hex(rand() . 'some string') });
$i->insert;
$i->data({ name => 'john', surname => 'doe', birthday => '04/07/1976'});
#--------------------------------
# this is the important bit
# assigning to the HoH directly
#--------------------------------
$i->data->{books} = ['1984', 'Wuthering heights'];
$i->update;
Foo::人们看起来像这样:
__PACKAGE__->add_columns(
"id",
{ data_type => "varchar", is_nullable => 0, size => 32 },
"data",
{ data_type => "json", is_nullable => 1, accessor => '_data', },
);
__PACKAGE__->set_primary_key(qw/id/);
use JSON::XS;
use Data::Dump qw/dump/;
sub data {
my ($self, $value) = @_;
if(@_ > 1) {
my $value = encode_json($value);
$self->_data($value);
}
$value = decode_json($self->_data());
return $value;
}
但是这不起作用 - 唯一能做的就是将散列存储在一个临时值中,更改它,然后再次存储它,如下所示:
my $v = $i->data;
$v->{books} = ['1984', 'Wuthering heights'];
$i->data($v)
$i->update;
有更简洁的方法吗?
您正在寻找的是像 https://metacpan.org/pod/DBIx::Class::InflateColumn::Serializer::JSYNC 这样的 InflateColumn。
你自己也可以轻松写一个。
不要忘记,当您调用 add_column 时,DBIC 只会为您生成列访问器,并且它们的名称是可配置的,因此可以重命名它们并从您自己的访问器方法中调用它们。
或者你使用 Moo(se) 方法修饰符。
Inflating/deflating abraxxa 的答案中的列工作正常,但我仍然必须显式更新该列,否则不会存储对取消引用字段的分配。
我最终向该列添加了一个属性,并在更新时添加了一个 before
Moose 挂钩,如下所示:
__PACKAGE__->add_columns(
"id" => { data_type => "varchar", is_nullable => 0, size => 32 },
"data" => {
data_type => "json",
is_nullable => 1,
always_update => 1
},
);
和
before 'update' => sub {
my $self = shift;
my %c = $self->get_columns;
for (grep { $self->result_source->column_info($_)->{always_update} } keys %c) {
$self->make_column_dirty($_);
}
};
这样我就不需要每次都显式地调用 data
列的更新。
我不知道这是不是一个坏主意 - 欢迎评论。
我有一个带有 JSON 列的 Postgres 数据库,我想为此做这样的事情:
use lib './lib';
use Digest::MD5 qw(md5 md5_hex);
use Data::Dump qw/dump/;
use Foo; # isa 'DBIx::Class::Schema';
$f = Foo->connect('dbi:Pg:database=mydb');
my $i = $f->resultset('People')->create({ id => md5_hex(rand() . 'some string') });
$i->insert;
$i->data({ name => 'john', surname => 'doe', birthday => '04/07/1976'});
#--------------------------------
# this is the important bit
# assigning to the HoH directly
#--------------------------------
$i->data->{books} = ['1984', 'Wuthering heights'];
$i->update;
Foo::人们看起来像这样:
__PACKAGE__->add_columns(
"id",
{ data_type => "varchar", is_nullable => 0, size => 32 },
"data",
{ data_type => "json", is_nullable => 1, accessor => '_data', },
);
__PACKAGE__->set_primary_key(qw/id/);
use JSON::XS;
use Data::Dump qw/dump/;
sub data {
my ($self, $value) = @_;
if(@_ > 1) {
my $value = encode_json($value);
$self->_data($value);
}
$value = decode_json($self->_data());
return $value;
}
但是这不起作用 - 唯一能做的就是将散列存储在一个临时值中,更改它,然后再次存储它,如下所示:
my $v = $i->data;
$v->{books} = ['1984', 'Wuthering heights'];
$i->data($v)
$i->update;
有更简洁的方法吗?
您正在寻找的是像 https://metacpan.org/pod/DBIx::Class::InflateColumn::Serializer::JSYNC 这样的 InflateColumn。
你自己也可以轻松写一个。
不要忘记,当您调用 add_column 时,DBIC 只会为您生成列访问器,并且它们的名称是可配置的,因此可以重命名它们并从您自己的访问器方法中调用它们。
或者你使用 Moo(se) 方法修饰符。
Inflating/deflating abraxxa 的答案中的列工作正常,但我仍然必须显式更新该列,否则不会存储对取消引用字段的分配。
我最终向该列添加了一个属性,并在更新时添加了一个 before
Moose 挂钩,如下所示:
__PACKAGE__->add_columns(
"id" => { data_type => "varchar", is_nullable => 0, size => 32 },
"data" => {
data_type => "json",
is_nullable => 1,
always_update => 1
},
);
和
before 'update' => sub {
my $self = shift;
my %c = $self->get_columns;
for (grep { $self->result_source->column_info($_)->{always_update} } keys %c) {
$self->make_column_dirty($_);
}
};
这样我就不需要每次都显式地调用 data
列的更新。
我不知道这是不是一个坏主意 - 欢迎评论。