7

我目前正在尝试使用 DBIx 实现以下场景:

表格产品包含“通用产品”和“捆绑产品”(捆绑产品是通用产品的集合):

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中。

现在我想将此信息封装在类标识中:我想要以下类:

  • 产品(type无所谓)
  • 捆绑产品(type='捆绑')
  • 一般产品(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;

获取所有通用产品。虽然生成的对象是 instance BundleProduct,但生成的 SQL 包含类的 WHERE 条件GeneralProducttype='general')。更糟糕的是:如果我尝试获取( and的Product基类)条件= 'general' 也适用!似乎其中的定义覆盖了所有其他定义。BundleProductGeneralProducttypeGeneralProduct

我的设计有什么问题?

4

3 回答 3

4

resultset_attributes不推荐使用。Product您应该为with 方法bundle_products和实现一个结果集类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' }); }

然后您可以像这样搜索特定产品:

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

请参阅resultset_attributes 的文档

也看看DBIx::Class::DynamicSubclass。它在对结果进行子类化时添加了一些有用的功能。

于 2013-03-07T12:53:03.553 回答
0

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

所以我不再使用它们了。我使用外键关系和单个表或包含所有代码的组合表:

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

然后我在 product.product_type_id = code_table.id 上从 product 加入 product_type

这种技术使应用程序的实现变得非常容易,但代价是在项目开始时需要进行一些额外的数据库管理。

于 2012-10-11T20:03:18.413 回答
0

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

很惊讶它没有给出明确的错误,但也许在下面添加(到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"],
  },
},

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

手指越过这件作品。如果不尝试删除default_value,看看这会如何影响事情。

于 2012-10-11T18:39:02.090 回答