[Dbix-class] complex relationships II

Matt S Trout dbix-class at trout.me.uk
Mon Sep 24 21:56:15 GMT 2007


On Mon, Sep 24, 2007 at 09:11:19AM -0700, Ben Hitz wrote:
> 
> BUMP!
> >
> >Hi, we are in the process of replacing an old, hand-rolled API (and  
> >bags-o-sql) with DBIc.  Our Oracle database is pretty large (~110  
> >tables) with some complicated relationships.  We have used  
> >DB::Mod::Schema::Loader::Oracle to generate some table classes, but  
> >of course they don't find all the many-to-manys.
> >
> >Looking for some advice on how to implement a couple types of  
> >relationships. This is the second of two emails, and I think is  
> >where it starts to get ugly
> >"Triple Linking Tables"
> >e.g.
> >
> >
> >CREATE TABLE GO_ANNOTATION
> >(GO_ANNOTATION_NO NUMBER(10) NOT NULL
> >,GO_NO NUMBER(10) NOT NULL
> >,FEATURE_NO NUMBER(10) NOT NULL
> >,GO_EVIDENCE VARCHAR2(40) NOT NULL
> >,ANNOTATION_TYPE VARCHAR2(40) NOT NULL
> >,SOURCE VARCHAR2(40) NOT NULL
> >,DATE_LAST_REVIEWED DATE DEFAULT SYSDATE NOT NULL
> >,DATE_CREATED DATE DEFAULT SYSDATE NOT NULL
> >,CREATED_BY VARCHAR2(12) DEFAULT SUBSTR(USER,1,12) NOT NULL
> >)
> >
> >
> >ALTER TABLE GO_ANNOTATION
> >ADD (CONSTRAINT GO_ANNOTATION_UK UNIQUE
> >  (GO_NO
> >  ,FEATURE_NO
> >  ,GO_EVIDENCE
> >  ,ANNOTATION_TYPE
> >  ,SOURCE)
> >
> >ALTER TABLE GO_ANNOTATION ADD (CONSTRAINT
> >GOANN_GO_FK FOREIGN KEY
> >  (GO_NO) REFERENCES GO
> >  (GO_NO))
> >/
> >
> >ALTER TABLE GO_ANNOTATION ADD (CONSTRAINT
> >GOANN_FEAT_FK FOREIGN KEY
> >  (FEATURE_NO) REFERENCES FEATURE
> >  (FEATURE_NO) ON DELETE CASCADE)
> >/
> 
> >CREATE TABLE GO
> >(GO_NO NUMBER(10) NOT NULL
> >,GOID NUMERIC(10) NOT NULL
> >,GO_TERM VARCHAR2(240) NOT NULL
> >,GO_ASPECT VARCHAR2(40) NOT NULL
> >,GO_DEFINITION VARCHAR2(2000)
> >,DATE_CREATED DATE DEFAULT SYSDATE NOT NULL
> >,CREATED_BY VARCHAR2(12) DEFAULT SUBSTR(USER,1,12) NOT NULL
> >)
> >
> >ALTER TABLE GO
> >ADD (CONSTRAINT GO_PK PRIMARY KEY
> >  (GO_NO)
> >
> 
> >ALTER TABLE GO
> >ADD (CONSTRAINT GO_TERM_UK UNIQUE
> >  (GO_TERM
> >  ,GO_ASPECT)
> >
> >ALTER TABLE GO
> >ADD (CONSTRAINT GO_GOID_UK UNIQUE
> >  (GOID)
> 
> >
> >CREATE TABLE FEATURE
> >(FEATURE_NO NUMBER(10) NOT NULL
> >,FEATURE_NAME VARCHAR2(40) NOT NULL
> >,DBXREF_ID VARCHAR2(40) NOT NULL
> >,FEATURE_TYPE VARCHAR2(40) NOT NULL
> >,SOURCE VARCHAR2(40) NOT NULL
> >,COORD_VERSION DATE
> >,STOP_COORD NUMBER(10)
> >,START_COORD NUMBER(10)
> >,STRAND VARCHAR2(1)
> >,GENE_NAME VARCHAR2(10)
> >,NAME_DESCRIPTION VARCHAR2(100)
> >,GENETIC_POSITION NUMBER(5,2)
> >,HEADLINE VARCHAR2(960)
> >,DATE_CREATED DATE DEFAULT SYSDATE NOT NULL
> >,CREATED_BY VARCHAR2(12) DEFAULT SUBSTR(USER,1,12) NOT NULL
> >)
> >
> >
> >ALTER TABLE FEATURE
> >ADD (CONSTRAINT FEATURE_PK PRIMARY KEY
> >  (FEATURE_NO)
> >
> >ALTER TABLE FEATURE
> >ADD (CONSTRAINT FEAT_DBXREF_ID_UK UNIQUE
> >  (DBXREF_ID)
> >
> 
> >CREATE TABLE GO_REF
> >(GO_REF_NO NUMBER(10) NOT NULL
> >,REFERENCE_NO NUMBER(10) NOT NULL
> >,GO_ANNOTATION_NO NUMBER(10) NOT NULL
> >,HAS_QUALIFIER VARCHAR2(1) NOT NULL
> >,HAS_SUPPORTING_EVIDENCE VARCHAR2(1) NOT NULL
> >,DATE_CREATED DATE DEFAULT SYSDATE NOT NULL
> >,CREATED_BY VARCHAR2(12) DEFAULT SUBSTR(USER,1,12) NOT NULL
> >)
> >
> >
> >ALTER TABLE GO_REF
> >ADD (CONSTRAINT GO_REF_UK UNIQUE
> >  (REFERENCE_NO
> >  ,GO_ANNOTATION_NO)
> >
> >ALTER TABLE GO_REF ADD (CONSTRAINT
> >GOREF_REF_FK FOREIGN KEY
> >  (REFERENCE_NO) REFERENCES REFERENCE
> >  (REFERENCE_NO) ON DELETE CASCADE)
> >/
> >
> >ALTER TABLE GO_REF ADD (CONSTRAINT
> >GOREF_GOANN_FK FOREIGN KEY
> >  (GO_ANNOTATION_NO) REFERENCES GO_ANNOTATION
> >  (GO_ANNOTATION_NO) ON DELETE CASCADE)
> >/
> 
> >
> >CREATE TABLE REFERENCE
> >(REFERENCE_NO NUMBER(10) NOT NULL
> >,SOURCE VARCHAR2(40) NOT NULL
> >,STATUS VARCHAR2(40) NOT NULL
> >,PDF_STATUS VARCHAR2(40) NOT NULL
> >,DBXREF_ID VARCHAR2(40) NOT NULL
> >,CITATION VARCHAR2(480) NOT NULL
> >,YEAR NUMBER(4) NOT NULL
> >,PUBMED NUMBER(10)
> >,DATE_PUBLISHED VARCHAR2(40)
> >,DATE_REVISED NUMBER(8)
> >,ISSUE VARCHAR2(40)
> >,PAGE VARCHAR2(40)
> >,VOLUME VARCHAR2(40)
> >,TITLE VARCHAR2(400)
> >,JOURNAL_NO NUMBER(10)
> >,BOOK_NO NUMBER(10)
> >,DATE_CREATED DATE DEFAULT SYSDATE NOT NULL
> >,CREATED_BY VARCHAR2(12) DEFAULT SUBSTR(USER,1,12) NOT NULL
> >)
> >ALTER TABLE REFERENCE
> >ADD (CONSTRAINT REFERENCE_PK PRIMARY KEY
> >  (REFERENCE_NO)
> >
> >ALTER TABLE REFERENCE ADD (CONSTRAINT
> >REF_BOOK_FK FOREIGN KEY
> >  (BOOK_NO) REFERENCES BOOK
> >  (BOOK_NO))
> >/
> >
> >ALTER TABLE REFERENCE ADD (CONSTRAINT
> >REF_JOUR_FK FOREIGN KEY
> >  (JOURNAL_NO) REFERENCES JOURNAL
> >  (JOURNAL_NO))
> >
> 
> I didn't get a reply to this, so I am rephrasing it:
> 
> DB::Mod.pm is a subclass of DBIx::Class::Schema, the DB::Mod::Table  
> classes are subclasses of DBIx::Class
> 
> And some relationships:
> DB::Mod::Feature->has_many(
>   "go_annotations",
>   "DB::Mod::Go_annotation",
>   { "foreign.feature_no" => "self.feature_no" },
> );
> 
> DB::Mod::Go_annotation->belongs_to("go_no", "DB::Mod::Go", { go_no =>  
> "go_no" });
> DB::Mod::Go_annotation->belongs_to(
>   "feature_no",
>   "DB::Mod::Feature",
>   { feature_no => "feature_no" },
> );
> DB::Mod::Go_annotation->has_many(
>   "go_refs",
>   "DB::Mod::Go_ref",
>   { "foreign.go_annotation_no" => "self.go_annotation_no" },
> );
> 
> DB::Mod::Go_ref->belongs_to(
>   "go_annotation_no",
>   "DB::Mod::Go_annotation",
>   { go_annotation_no => "go_annotation_no" },
> );
> DB::Mod::Go_ref->belongs_to(
>   "reference_no",
>   "DB::Mod::Reference",
>   { reference_no => "reference_no" },
> );
> 
> So we can say:
> DB::Mod::Feature->many_to_many(goes => 'go_annotations', 'go_no');
> as well as the reverse (obverse?)
> DB::Mod::Go->many_to_many(features => 'go_annotations', 'feature_no');
> 
> and
> DB::Mod::Go_annotation->many_to_many(references=>'go_refs',  
> 'reference_no');
> and the reverse
> DB::Mod::Reference->many_to_many(go_annotations=>'go_refs',  
> 'go_annotation_no');
> 
> BUT say I want the following method:
> 
> DB::Mod::Feature->go_references (which returns an array of  
> DB::Mod::Reference objects)
> 
> We cannot make a many_to_many between Feature and Go_ref, because  
> go_annotation does not belong_to go_ref (it has many)
> 
> What is the preferred way of setting this up?
> Just make a method in DB::Mod::Feature:
> sub go_references {
> 
> 	@refs = ();
> 	for $goAn ($self->go_annotations) {
> 	      @refs = (@refs, @{$goAn->refs});
>         }
> 	# actually we should probably put them in a hash to uniquify them...
> 	return \@refs;
> }
> 
> I have a few other cases in the schema where I want to span a  
> has_many -> many_to_many... should I my own relationship, or just  
> write specific methods (yes, I realize this is a style question)

All those will tend to return a resultset so

sub go_references { shift->go_annotations->search_related('refs', @_); }

should do the trick.

Must better phrasing of the question this time, thanks :)

-- 
      Matt S Trout       Need help with your Catalyst or DBIx::Class project?
   Technical Director                    http://www.shadowcat.co.uk/catalyst/
 Shadowcat Systems Ltd.  Want a managed development or deployment platform?
http://chainsawblues.vox.com/            http://www.shadowcat.co.uk/servers/



More information about the DBIx-Class mailing list