DBIx and inheritance in Perl

I'm currently trying to implement the following scenario with DBIx:

The table products contains "general products" and "bundle products" (bundle products are collections of general products):

package Product;
use base 'DBIx::Class::Core';
__PACKAGE__->table("products");
__PACKAGE__->add_columns(
  "productId",
  { data_type => "varchar", is_nullable => 0, size => 10},
  "name",
  { data_type => "varchar", is_nullable => 1, size => 150},
  "type",
  {
     data_type => "enum",
     default_value => "general",
     extra => {
       list => ["general", "bundle"],
     },
     is_nullable => 0,
  });

As you can see, wether the product is a general product or a bundle product is saved in the column type .

Now I would like to encapsulate this information in the class identity: I would like to have following classes:

  • Product ( type does not matter)
  • BundleProduct ( type = 'bundle')
  • GeneralProduct ( type = 'general')
  • I wrote:

    package BundleProduct;
    use base 'Product';
    
    __PACKAGE__->resultset_attributes({ where => { 'type' => 'bundle' } });
    1;
    

    and

    package GeneralProduct;
    use base 'Product';
    
    __PACKAGE__->resultset_attributes({ where => { 'type' => 'general' } });
    1;
    

    But when executing

    my @allProducts = $schema->resultset('BundleProduct')->all;
    

    all general products are fetched. Although the resulting objects are of instance BundleProduct , the generated SQL contains the WHERE-condition of the class GeneralProduct ( type = 'general'). Even worse: If I try to fetch a Product (base class of BundleProduct and GeneralProduct ) the condition type = 'general' is applied, too! It seems that the definition within GeneralProduct overwrites all other definitions.

    What is wrong with my design?


    The usage of resultset_attributes is not recommended. You should implement a result set class for Product with methods bundle_products and general_products :

    package My::Schema::ResultSet::Product;
    use base 'DBIx::Class::ResultSet';
    
    sub bundle_products  { shift->search({ type => 'bundle' }); }
    sub general_products { shift->search({ type => 'general' }); }
    

    Then you can search specific products like this:

    $schema->resultset('Product')->bundle_products->all;
    $schema->resultset('Product')->general_products->all;
    

    See the documentation of resultset_attributes.

    Also have a look at DBIx::Class::DynamicSubclass. It adds some useful features when subclassing results.


    This might be slightly OT, but I seem to always run into some insidious application implementation problem when dealing with enum data types in my schemas.

    So I don't use them any more. I use foreign key relationships and either individual tables or a combined table holding all codes:

    <id, code_type, code_name> 
    < 1, 'product_type', 'bundle'>
    < 2, 'product_type', 'general'>
    

    and then I join from product to product_type on product.product_type_id = code_table.id

    This technique has made application implementation much, much easier at the cost of some additional database management in the beginning of the project.


    It may always be defaulting to general because the data is not being inflated to an Enum object?

    Surprised that it doesn't give a clear error but perhaps adding below (to Product package) will fix your problem:

    __PACKAGE__->load_components(qw/InflateColumn::Object::Enum/);
    

    Additional to above also try adding is_enum => 1 to your type column definition:

    type => {
      data_type     => "enum",
      is_enum       => 1,  
      default_value => "general",
      is_nullable   => 0,
      extra => {
        list => ["general", "bundle"],
      },
    },
    

    NB. This should enforce the use of the inflation object ( Object::Enum ) whereas without it I believe it tries to use the enum native to the RDBMS you're using (if its present).

    Fingers crossed this works. If not try removing the default_value to see how this affects things.

    链接地址: http://www.djcxy.com/p/64714.html

    上一篇: 为住宅销售信息:房地产API

    下一篇: DBIx和Perl中的继承