2012-10-11 29 views
7

tôi đang cố gắng để thực hiện các tình huống sau với DBIx: DBIx và thừa kế trong Perl

Bảng

sản phẩm chứa "sản phẩm chung" và "sản phẩm bó" (bó sản phẩm này là bộ sưu tập các sản phẩm nói chung):

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

Như bạn có thể thấy, thời tiết các sản phẩm là một vị tướng sản phẩm hoặc một sản phẩm được lưu trong cột loại.

Bây giờ tôi muốn để đóng gói thông tin này trong bản sắc lớp: Tôi muốn có các lớp sau:

  • Sản phẩm (type không quan trọng)
  • BundleProduct (type = 'bó')
  • GeneralProduct (type = 'chung')

tôi đã viết:

012.
package BundleProduct; 
use base 'Product'; 

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

package GeneralProduct; 
use base 'Product'; 

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

Nhưng khi thực hiện

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

tất cả sản phẩm chung được lấy. Mặc dù các đối tượng kết quả là ví dụ BundleProduct, SQL được tạo ra chứa điều kiện WHERE của lớp GeneralProduct (type = 'chung'). Thậm chí tệ hơn: Nếu tôi cố gắng lấy một số Product (lớp cơ sở là BundleProductGeneralProduct), điều kiện type = 'chung' cũng được áp dụng! Dường như định nghĩa trong phạm vi GeneralProduct sẽ ghi đè tất cả các định nghĩa khác.

Điều gì sai với thiết kế của tôi?

Trả lời

0

Nó luôn có thể được mặc định là chung vì dữ liệu không bị thổi phồng vào đối tượng Enum?

Ngạc nhiên rằng nó không đưa ra một lỗi rõ ràng nhưng có lẽ thêm dưới đây (để Product gói) sẽ khắc phục vấn đề của bạn:

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

bổ sung để ở trên cũng thử thêm is_enum => 1-kiểu định nghĩa cột của bạn:

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

NB. Điều này nên thực thi việc sử dụng các đối tượng lạm phát (Object::Enum) trong khi không có nó tôi tin rằng nó cố gắng sử dụng enum bản địa cho RDBMS bạn đang sử dụng (nếu có).

Ngón tay đã vượt qua tác phẩm này.Nếu không thử xóa default_value để xem điều này ảnh hưởng đến mọi thứ như thế nào.

+0

@dreagtun Cảm ơn bạn, nhưng tôi nghĩ rằng InflateColumn :: Object :: Enum chỉ được chỉ định để chuyển đổi trường 'varchar' thành trường' enum' trong ứng dụng. [link] (http://search.cpan.org/~jmmills/DBIx-Class-InflateColumn-Object-Enum-0.04/lib/DBIx/Class/InflateColumn/Object/Enum.pm) –

+0

Nhìn vào các bài kiểm tra được cung cấp bởi mô đun 'DBIx :: Class :: InflateColumn :: Object :: Enum', tác giả luôn tải thành phần và đặt' is_enum => 1'. Đây là bài kiểm tra phù hợp với những gì bạn đang cố gắng làm trong ví dụ của bạn: https://metacpan.org/source/JMMILLS/DBIx-Class-InflateColumn-Object-Enum-0.04/t/lib/TestDB/NativeEnumNoneNullable.pm Tác giả có lẽ quá nhiệt tình nhưng có lẽ đáng để thử. Ngoài ra tác giả không cung cấp các thử nghiệm 'default_value' để có thể có vấn đề ở đó? Dù sao tôi đã cập nhật câu trả lời của tôi cho phù hợp. – draegtun

0

Điều này có thể hơi OT, nhưng dường như tôi luôn gặp phải một số vấn đề triển khai ứng dụng ngớ ngẩn khi xử lý các loại dữ liệu enum trong lược đồ của tôi.

Vì vậy, tôi không sử dụng chúng nữa. Tôi sử dụng các mối quan hệ ngoại chủ chốt và một trong hai bảng cá nhân hoặc một bảng kết hợp giữ tất cả các mã:

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

và sau đó tôi tham gia từ sản phẩm đến PRODUCT_TYPE trên product.product_type_id = code_table.id

Kỹ thuật này đã thực hiện ứng dụng dễ dàng hơn nhiều với chi phí quản lý cơ sở dữ liệu bổ sung vào đầu dự án.

+1

Bạn có thể tránh tham gia bằng cách tạo một bảng 'product_types' với một trường đơn lẻ, tên kiểu, có một ràng buộc duy nhất và là khóa ngoài trong bảng' products'. Khóa ngoài sẽ thực thi tập hợp các giá trị giới hạn cho trường, và vì khóa là tên chứ không phải là một số, nên không cần phải thực hiện thêm các phép nối. – friedo

+0

Đúng. nhưng tôi không còn sử dụng dữ liệu cho khóa. Cho dù tôi có cố gắng thế nào đi chăng nữa, ai đó cuối cùng cũng muốn thay đổi dữ liệu quan trọng và sau đó bạn có tất cả các công việc bổ sung nhận được những cập nhật đó. Nếu mã được sử dụng thường xuyên, nó sẽ được trong bộ nhớ để tham gia sẽ không mất nhiều thời gian. Tại sao trên trái đất là tất cả mọi người sợ tham gia? –

4

Không nên sử dụng resultset_attributes. Bạn nên thực hiện một bộ lớp kết quả cho Product với các phương pháp 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' }); } 

Sau đó, bạn có thể tìm kiếm các sản phẩm cụ thể như thế này:

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

Xem documentation of resultset_attributes.

Ngoài ra, hãy xem DBIx::Class::DynamicSubclass. Nó cho biết thêm một số tính năng hữu ích khi phân lớp kết quả.

+0

++ cho DBIx :: Class :: DynamicSubclass trong trường hợp này – tospo

+0

... hoặc làm điều đó "bằng tay" như được mô tả trong sách dạy nấu ăn: http://search.cpan.org/~ribasushi/DBIx-Class-0.08250/ lib/DBIx/Class/Manual/Cookbook.pod # Dynamic_Sub-classing_DBIx :: Class_proxy_classes_% 28AKA_multi-class_object_inflation_from_one_table% 29 – tospo