【问题标题】:Is this schema and DBIC code efficient?这种模式和 DBIC 代码是否有效?
【发布时间】:2013-11-24 11:43:39
【问题描述】:

我正在尝试确定我是否正在使用 SQL 和 DBIx::Class 以正确的方式解决以下问题,因为我对这两者都很陌生。

我有一个包含 3 个表、设备、对象和网络的架构

一个设备可以有 0..1 到多个对象 一个对象可以有 1 个网络,但一个网络可以属于 0...许多设备。

我试图在图中所示的架构中捕捉到这种关系。

这里是相关的 Schema。

设备

__PACKAGE__->table("Device");

__PACKAGE__->add_columns(
  "devicename",
  { data_type => "varchar", is_nullable => 0, size => 50 },
  "devicetype",
  { data_type => "varchar", is_nullable => 0, size => 20 },
  "deviceid",
  {  data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
);

__PACKAGE__->set_primary_key("deviceid");
__PACKAGE__->has_many(
  "objects",
  "TestApp::Schema::Result::Object",
  { "foreign.device_deviceid" => "self.deviceid" },
  { cascade_copy => 0, cascade_delete => 0 },

对象

__PACKAGE__->table("Object");

__PACKAGE__->add_columns(
  "objectid",
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "objectname",
  { data_type => "varchar", is_nullable => 0, size => 100 },
  "objecttype",
  { data_type => "varchar", is_nullable => 0, size => 20 },
  "device_deviceid",
  {  data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
  "network_networkid",
  {    data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
);

__PACKAGE__->set_primary_key("objectid");

__PACKAGE__->belongs_to(
  "device_deviceid",
  "TestApp::Schema::Result::Device",
  { deviceid => "device_deviceid" },
  { is_deferrable => 1, on_delete => "NO ACTION", on_update => "NO ACTION" },
);

 __PACKAGE__->belongs_to(
  "network_networkid",
  "TestApp::Schema::Result::Network",
  { networkid => "network_networkid" },
  {
    is_deferrable => 1,
    join_type     => "LEFT",
    on_delete     => "NO ACTION",
    on_update     => "NO ACTION",
  },
);

网络

__PACKAGE__->table("network");

__PACKAGE__->add_columns(
   "networkid",
 { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "network",
  { data_type => "varchar", is_nullable => 1, size => 15 },
  "netmask",
  { data_type => "varchar", is_nullable => 1, size => 15 },
  "cidr",
   { data_type => "integer", is_nullable => 1 },
 );

__PACKAGE__->set_primary_key("networkid");

__PACKAGE__->has_many(
 "objects",
  "TestApp::Schema::Result::Object",
  { "foreign.network_networkid" => "self.networkid" },
  { cascade_copy => 0, cascade_delete => 0 },
);

对于我的测试数据,我将插入如下数据。有没有更有效的方法?

#get result sets
my $network_rs = $schema->resultset('Network');
my $device_rs = $schema->resultset('Device');

#create a new device
my $new_device = $device_rs->create( { devicename => 'test_device', devicetype => 'test_dt'});

#create a new network if it doesn't exist.
my $new_network = $network_rs->find_or_create({ network => '1.1.1.1', netmask => '255.255.255.0', cidr => '24' });

#Add two objects and set the foreign key for the network table for the newly created network above.
$new_device->objects->create( { objectname => 'networkobj1',network_networkid => $new_network->networkid });
$new_device->objects->create( { objectname => 'networkobj2',network_networkid => $new_network->networkid });

要查看分配给每个网络的网络,我只需执行以下操作;

my @deviceObjects = $new_device->objects();

foreach my $object (@deviceObjects) 
{ 
print $object->objectname . " contains the following network:\n";  
print $object->network_networkid->network . "\n";
print $object->network_networkid->netmask . "\n";
print $object->network_networkid->cidr . "\n";
} 

【问题讨论】:

    标签: mysql sql perl schema dbix-class


    【解决方案1】:

    关于你的测试数据插入,有一种更有效的方法(编写它),DBIC 可以根据你告诉它的关系一次做一大堆插入,我们称之为“multicreate”,所以使用你的例子:

    # get main device resultset:
    my $device_rs = $schema->resultset('Device');
    
    # create all the things:
    $device_rs->create({ 
       # Device columns:
       devicename => 'test_device', 
       devicetype => 'test_dt',
       # Objects:
       objects => [
         {
            objectname => 'networkobj1',
            # network for this object:
            network_networkid => {
               network => '1.1.1.1', netmask => '255.255.255.0', cidr => '24',
            }
         },
         {
            objectname => 'networkobj2',
            # network for this object:
            network_networkid => {
               network => '1.1.1.1', netmask => '255.255.255.0', cidr => '24',
            }
         }
       ]
    });
    

    请注意,指定网络数据不应该让您插入两个网络行,它将使用 find_or_new 创建该行,因此应该找到创建的第一个,用于第二个。

    【讨论】:

      【解决方案2】:

      基本上你做的一切都是正确的。 您的对象表通常称为桥接或多对多辅助表。 要直接从设备访问其网络,您可以添加 many_to_many 辅助方法,请参阅 DBIx::Class::Relationship 文档。 有一些模块可以用(测试)数据填充数据库,例如 DBIx::Class::Fixtures。

      对于关系(以及 DBIx::Class::Schema::Loader 从现有数据库生成的内容)的推荐命名对于返回单行的关系(belongs_to、has_one 和 may_have)是单数的,对于返回一个行列表(has_many)。 使用 device->objects->network 读取更自然,包括存储外键的列名没有多大意义。

      除了这些小事,还有一个好的开始! 加入 irc.perl.org 中的#dbix-class 以获得实时帮助。

      【讨论】:

      • 感谢 abraxxa,这很有帮助。关于对象表是一个桥梁,我可以做到这一点,但是我实际上有另一个表(规则集),它需要与对象表具有一对多的关系,我需要在对象表基于其对象名称。我假设这仍然可以,因为我将在规则集和对象表之间建立实际关系?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-19
      • 1970-01-01
      • 2021-10-23
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多