2012-10-11 88 views
7
继承

我目前正在努力实现与DBIx以下情形:DBIx并在Perl

产品包含“一般产品”和“捆绑产品”(捆绑产品是普通产品的集合):

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, 
    }); 

正如你所看到的,羯羊产品是一般产品或产品被保存在列类型

现在我想封装在阶级认同这样的信息:我想有以下类:

  • 产品(type无所谓)
  • BundleProduct(type =“捆绑”)
  • GeneralProduct(type = '通用')

我写道:

package BundleProduct; 
use base 'Product'; 

__PACKAGE__->resultset_attributes({ where => { 'type' => 'bundle' } }); 
1; 

package GeneralProduct; 
use base 'Product'; 

__PACKAGE__->resultset_attributes({ where => { 'type' => 'general' } }); 
1; 

但执行

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

当所有一般产品被取出。虽然生成的对象具有实例BundleProduct,但生成的SQL包含类GeneralProducttype ='general')的WHERE条件。更糟的是:如果我尝试获取Product(基类BundleProductGeneralProduct),则也应用条件type ='general'!看来GeneralProduct中的定义会覆盖所有其他定义。

我的设计出了什么问题?

回答

0

它可能总是默认为一般因为数据没有被膨胀到一个枚举对象?

惊讶,它并没有给出明确的错误,但或许将低于(至Product包),将解决你的问题:

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

除了上述还尝试加入is_enum => 1类型列定义:

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

NB。这应该强制使用通货膨胀对象(Object::Enum),如果没有它,我相信它会尝试使用原生的RDBMS(如果存在)的枚举

手指穿过这件作品。如果不尝试删除default_value,看看这是如何影响的东西。

+0

@dreagtun谢谢你,但我认为InflateColumn :: Object :: Enum仅用于将'varchar'字段转换为应用程序中的'enum'字段。 [链接](http://search.cpan.org/~jmmill/DBIx-Class-InflateColumn-Object-Enum-0.04/lib/DBIx/Class/InflateColumn/Object/Enum.pm) –

+0

查看提供的测试通过'DBIx :: Class :: InflateColumn :: Object :: Enum'模块,作者总是加载组件并且设置'is_enum => 1'。以下是与您在示例中尝试使用的内容相匹配的测试:https://metacpan.org/source/JMMILLS/DBIx-Class-InflateColumn-Object-Enum-0.04/t/lib/TestDB/NativeEnumNoneNullable.pm作者也许是过于热心,但它可能值得一试。另外作者没有提供'default_value'测试,所以可能有问题呢?无论如何,我相应地更新了我的答案。 – draegtun

0

这可能会略微OT,但我似乎总是遇到一些阴险的应用程序实现问题,当处理我的模式中的枚举数据类型。

所以我不再使用它们。我使用外键关系以及各个表或组合表保存所有代码:

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

,然后我从产品加盟PRODUCT_TYPE上product.product_type_id = code_table.id

这种技术已提出申请执行在项目开始时以更多的数据库管理为代价,这非常容易。

+1

您可以通过在单个字段中使用'product_types'表来避免连接,类型名称具有唯一约束,并且是“产品”表中的外键。外键将强制该字段的有限的一组值,并且由于该键是名称而不是数字,所以不需要进行额外的连接。 – friedo

+0

是的。但我不再使用密钥数据。无论我尝试多么努力,最终都有人想要更改关键数据,然后完成所有更新。如果代码经常使用,它会在内存中,所以加入不会花费太多时间。为什么人人都害怕加入? –

4

不推荐使用resultset_attributes。您应该实现的结果集类Product与方法bundle_productsgeneral_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' }); } 

然后你就可以搜索特定的产品是这样的:

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

documentation of resultset_attributes

也看看DBIx::Class::DynamicSubclass。子类化结果时,它增加了一些有用的功能。

+0

++对于此场景中的DBIx :: Class :: DynamicSubclass – tospo

+0

...或者如食谱中所述“手动”执行:http://search.cpan.org/~ribasushi/DBIx-Class-0.08250/ LIB/DBIx /等级/手动/ Cookbook.pod#Dynamic_Sub-classing_DBIx :: Class_proxy_classes_%28AKA_multi-class_object_inflation_from_one_table%29 – tospo