DBIX::Class subclassing result class

2019-09-05 22:57发布

问题:

I am trying to use a common base class for multiple result classes in DBIX::Class. Reason is - I have few tables with same structure but different names.

Here is my base class

use utf8;
package myapp::Schema::tablebase;

use strict;
use warnings;

use base 'DBIx::Class::Core';

__PACKAGE__->table("unknown");

__PACKAGE__->add_columns(
  "id",
  { data_type => "smallint", is_nullable => 0 }

  #, ... and lot more
);

Here is actual result class

package myapp::Schema::Result::ActualTable;
use base 'myapp::Schema::tablebase';
 # Correct table name
__PACKAGE__->table('patient2');
1;

I am getting compilation error for this effort. Please help me on this.

Update:

The error I am getting is -

DBIx::Class::Schema::catch {...} (): Attempt to load_namespaces() class myapp::Schema::Result::ActualTable failed - are you sure this is a real Result Class?: Can't locate object method "result_source_instance" via package "myapp::Schema::Result::ActualTable" at C:/Strawberry/perl/site/lib/DBIx/Class/Schema.pm line 195. at C:/Strawberry/perl/site/lib/myapp/Schema.pm

回答1:

That should work, maybe because your base class is missing the true return value (1;) at the end?

You can also use DBIx::Class::Helper::Row::SubClass if you prefer a neater solution that also fixes relationships that your base class might have defined.



回答2:

Here are the changes I made to methods "subclass" and "generate_relationships", to preserve various relationships among global and client specific tables. Also I had to drop reverse relationships form global to many client specific tables.

sub subclass {
   my $self = shift;
   my $client_id = shift;
   $self->set_table($client_id);
   $self->generate_relationships($client_id);
}

sub generate_relationships {
  my $self = shift;
  my $client_id = shift;
  my ($namespace) = get_namespace_parts($self);
  foreach my $rel ($self->relationships) {
    my $rel_info = $self->relationship_info($rel);
    my $class = $rel_info->{class};

    assert_similar_namespaces($self, $class);
    my (undef, $result) = get_namespace_parts($class);

    eval "require $class";
    # relation of self with global table e.g. person to zipcode or guarantor2 to person
    # Copy relation as is 
    if($class->is_global == 1){
      $self->add_relationship(
       $rel,
       "${namespace}::$result",
       $rel_info->{cond},
       $rel_info->{attrs}
      );
    }else{
    # relation with client specific table e.g. patient2 has many guarantor2, person has many guarantor2
    # skip if self is global (   person has many guarantor2/3/4 etc)
      if($client_id ne ''){        
    # need client id mention in result class with which self is related
        $self->add_relationship(
          $rel,
          "${namespace}::$result"."$client_id",
          $rel_info->{cond},
          $rel_info->{attrs}
        );
      }
    }        
  };
}

For each subclass I am passing client_id as argument, which is blank for global tables.