zooey has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, i want to create simple dictionary application, and have three tables, but I don't know how to set up many to many relationship between them i tried many combinations. Here is how i did it: englishword table: (eng_id, englishword) skwordmeanings table: (sk_id, skword) en_to_sk table: (eng_id,sk_id)

###################################################################### +########## # Package MyDictionary::DBI # # Represents object oriented form of my Database package MyDictionary::DBI; use base "Class::DBI::SQLite"; MyDictionary::DBI->set_db('Main', "dbi:SQLite:dbname=Dictionary.db"); ###################################################################### +########## # Package MyDictionary::Engword # # Represent englishword table package MyDictionary::Engword; use base "MyDictionary::DBI"; MyDictionary::Engword->set_up_table("englishword"); MyDictionary::Engword->has_many('translations',['MyDictionary::En_To_S +k' => 'skword'], 'engword'); ###################################################################### +########## # Package MyDictionary::Skword # # Represent skwordmeaning table package MyDictionary::Skword; use base "MyDictionary::DBI"; MyDictionary::Skword->set_up_table("skwordmeaning"); MyDictionary::Skword->has_many('translations',['MyDictionary::En_To_Sk +' => 'engword'], 'skword'); ###################################################################### +########## # Package MyDictionary::En_To_Sk # # Represents en_to_sk table package MyDictionary::En_To_Sk; use base "MyDictionary::DBI"; MyDictionary::En_To_Sk->set_up_table('en_to_sk'); MyDictionary::En_To_Sk->has_a('eng_id' => "MyDictionary::Engword"); MyDictionary::En_To_Sk->has_a('sk_id' => "MyDictionary::Skword"); ###################################################################### +##########

Thanks a lot

Replies are listed 'Best First'.
Re: Class DBI many to many
by Khen1950fx (Canon) on Jun 18, 2011 at 17:26 UTC
    Here's my take on it. I added CREATE TABLE and altered the beginning a little:
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper::Concise; package MyDictionary::DBI; use base qw(Class::DBI::SQLite); our (%SQL_CREATE); __PACKAGE__->set_db( 'Main', "dbi:SQLite:dbname=Dictionary.db", , ); package MyDictionary::Engword; use base qw( MyDictionary::DBI ); $MyDictionary::DBI::SQL_CREATE{englishwords} = " CREATE TABLE englishwords ( skword engword ); "; MyDictionary::Engword->table("englishwords"); MyDictionary::Engword->columns( Primary => qw/skword engword/ ); MyDictionary::Engword->has_many( sort => [ 'MyDictionary::En_To_Sk' => 'skword' ], 'engword' ); package MyDictionary::Skword; use base "MyDictionary::DBI"; MyDictionary::Skword->set_up_table("skwordmeaning"); MyDictionary::Skword->has_many( sort => [ 'MyDictionary::En_To_Sk' => 'engword' ], 'skword' ); package MyDictionary::En_To_Sk; use base "MyDictionary::DBI"; MyDictionary::En_To_Sk->set_up_table('en_to_sk'); MyDictionary::En_To_Sk->has_many('eng_id' => "MyDictionary::Engword"); MyDictionary::En_To_Sk->has_many('sk_id' => "MyDictionary::Skword" );
Re: Class DBI many to many
by martell (Hermit) on Jun 18, 2011 at 17:38 UTC

    One important remark in the documentation:

    When setting up the relationship the foreign class's has_a() declarations are examined to discover which of its columns reference our class. (Note that because this happens at compile time, if the foreign class is defined in the same file, the class with the has_a() must be defined earlier than the class with the has_many(). If the classes are in different files, Class::DBI should usually be able to do the right things, as long as all classes inherit Class::DBI before 'use'ing any other classes.)

    So this should work by reordering the declarations:

    package MyDictionary::En_To_Sk MyDictionary::En_To_Sk->columns(Primary => qw/id/); MyDictionary::En_To_Sk->columns(Essential => qw/eng_id sk_id/); # Declare the relationships MyDictionary::En_To_Sk->has_a('eng_id' => "MyDictionary::Engword"); MyDictionary::En_To_Sk->has_a('sk_id' => "MyDictionary::Skword"); package MyDictionary::Engword MyDictionary::Engword->columns(Primary => qw/id/); MyDictionary::Engword->has_many("translations", 'MyDictionary::En_To_S +k', 'eng_id'); package MyDictionary::Skword MyDictionary::Skword->columns(Primary => qw/id/); MyDictionary::Skword->has_many("translations", 'MyDictionary::En_To_Sk +', 'sk_id');

    I suppose you have defined the other columns. The construction "['MyDictionary::En_To_Sk' => 'engword']" in the 'has_many' function in the class 'MyDictionary::En_To_Sk' is only necessary when the values in 'eng_id' and 'sk_id' are not the primary keys used in the classes 'package MyDictionary::Engword' and 'package MyDictionary::Skword'.

    Hopes this helps.

    Martell

      Hi thanks for post i made it like you advised but it didn't help here is the code:

      ###################################################################### +########## # Package MyDictionary::DBI # # Represents object oriented form of my Database package MyDictionary::DBI; use base "Class::DBI::SQLite"; MyDictionary::DBI->set_db('Main', "dbi:SQLite:dbname=Dictionary.db"); ###################################################################### +########## # Package MyDictionary::En_To_Sk # # Represents en_to_sk table package MyDictionary::En_To_Sk; use base "MyDictionary::DBI"; MyDictionary::En_To_Sk->set_up_table('en_to_sk'); MyDictionary::En_To_Sk->columns(All => (eng_id sk_id)); MyDictionary::En_To_Sk->has_a('eng_id' => "MyDictionary::Engword"); MyDictionary::En_To_Sk->has_a('sk_id' => "MyDictionary::Skword"); # Package MyDictionary::Engword # # Represent englishword table package MyDictionary::Engword; use base "MyDictionary::DBI"; MyDictionary::Engword->set_up_table("englishword"); MyDictionary::Engword->columns(Primary => qw/eng_id/); MyDictionary::Engword->columns(All => (eng_id engword)); MyDictionary::Engword->has_many("translations", 'MyDictionary::En_To_S +k', 'eng_id'); #MyDictionary::Engword->has_many('translations',['MyDictionary::En_To_ +Sk' => 'skword'], 'engword'); ###################################################################### +########## # Package MyDictionary::Skword # # Represent skwordmeaning table package MyDictionary::Skword; use base "MyDictionary::DBI"; MyDictionary::Skword->set_up_table("skwordmeaning"); MyDictionary::Skword->columns(Primary => qw/sk_id/); MyDictionary::Skword->columns(All => (sk_id skword)); #MyDictionary::Skword->has_many('translations',['MyDictionary::En_To_S +k' => 'engword'], 'skword'); MyDictionary::Skword->has_many("translations", 'MyDictionary::En_To_Sk +', 'sk_id');
      Finally i've done it through DBIx it is better documented with more users. Thanks
Re: Class DBI many to many
by moritz (Cardinal) on Jun 18, 2011 at 12:52 UTC

    Sorry, please disregard this post - I thought about DBIx::Class, not Class::DBI.

    Change the has_a relations to belongs_to

    MyDictionary::En_To_Sk->belongs_to('eng', 'MyDictionary::Engword', 'en +g_id'); MyDictionary::En_To_Sk->belongs_to('sk', 'MyDictionary::Skword', 'sk_i +d');

    And then many_to_many:

    MyDictionary::Engword->many_to_many('sk_translations', 'translations', + 'sk'); MyDictionaly::Skword->many_to_many('en_translations', 'translations', +'en');