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

ご覧のとおり、商品が一般商品なのか、バンドル商品なのかが、列タイプに保存されます。

ここで、この情報をクラス ID にカプセル化したいと思います。次のクラスが必要です。

  • 商品(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;

すべての一般的な製品がフェッチされます。結果のオブジェクトは instance のものですがBundleProduct、生成された SQL にはクラスの WHERE 条件GeneralProduct( type= 'general') が含まれています。さらに悪いことに、( andProductの基本クラス)を取得しようとすると、条件= '一般' も適用されます! 内の定義が他のすべての定義を上書きしているようです。BundleProductGeneralProducttypeGeneralProduct

私のデザインのどこが悪いのですか?

4

3 に答える 3

4

の使用resultset_attributesは推奨されません。Productメソッド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

データが 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"],
  },
},

注意。これにより、インフレーション オブジェクト ( ) の使用が強制されるはずですが、それがないと、使用している RDBMS にネイティブな列挙型Object::Enumを使用しようとすると考えられます (存在する場合)。

指が交差したこの作品。そうでない場合は、 を削除して、default_valueこれがどのように影響するかを確認してください。

于 2012-10-11T18:39:02.090 に答える
0

これは少し OT かもしれませんが、スキーマで enum データ型を処理する際に、常に潜行的なアプリケーション実装の問題に遭遇するようです。

だから私はもうそれらを使用しません。外部キー関係と、個々のテーブルまたはすべてのコードを保持する結合テーブルのいずれかを使用します。

<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 に答える