Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Abstracting Class::DBI Database Connection Data

by gryphon (Abbot)
on Jun 08, 2004 at 20:37 UTC ( #362539=perlquestion: print w/replies, xml ) Need Help??

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

Greetings fellow monks,

I'm playing around with Class::DBI again, and I'd really like to pass dynamic DSNs and other database connection information to my parent class from the calling script or application module. I've been using Config::IniFiles for a while now, and I really like it and would like to continue to use it. I've been toying with a few ideas on how to combine my various wants, and here's what I've come up with.

#!/usr/bin/perl use strict; use warnings; use Config::IniFiles; my $cfg; BEGIN { $cfg = new Config::IniFiles( -file => 'settings.ini' ); $ENV{_MyCDBI} = join("\t", $cfg->val('Database', 'dsn'), $cfg->val('Database', 'Username'), $cfg->val('Database', 'Password') ); } use MyCDBI;

I'm using use here just because it's habit and because it runs parallel to using other CPAN stuff and my own application modules. However, I could just as easily require instead of use to simplify things.

my $cfg = new Config::IniFiles( -file => 'settings.ini' ); $ENV{_MyCDBI} = join("\t", $cfg->val('Database', 'dsn'), $cfg->val('Database', 'Username'), $cfg->val('Database', 'Password') ); require MyCDBI;

Either way, I just split the various bits inside my Class::DBI parent.

package MyCDBI; use base 'Class::DBI::mysql'; __PACKAGE__->connection(split("\t", $ENV{_MyCDBI}));

Now, this works just fine, and I'm more or less happy with it for my purposes, but it's far from optimum. First of all, I'm using poor-man's serialization of the bits for the database connection. A better solution would include the capability of sending stuff like {AutoCommit => 1} and whatever else. Plus, the code in the calling script is somewhat obnoxious. I'd love to use use if possible, but even without, it's three lines long. I know if merlyn saw this, he'd cringe and use a one-liner alternative.

So my question is thus: What are some better ways of doing this? (Better = less lines of code, more flexible data sent, more class encapsulation, more coffee, etc.) One thing I was thinking about was writing an abstraction class for my parent Class::DBI class. I've always hated having to refer to the subclass names multiple times.

my $obj = MyCDBI::SomeDBObj->retrieve(1); # versus my $cls = new MyCDBI; my $obj = $cls->SomeDBObj->retrieve(1);

But I can't really say exactly why I don't like this.

I've been reading about Class::DBI::Factory, but I have to admit that much of it goes way over my head. Should I just grin and deal with the learning curve? Or is there a simpler way?

code('Perl') || die;

Replies are listed 'Best First'.
Re: Abstracting Class::DBI Database Connection Data
by hardburn (Abbot) on Jun 08, 2004 at 20:40 UTC

    Read the section of the Class::DBI doc titled "Dynamic Database Connections / db_Main".

    send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.

      Greetings hardburn,

      I have. Many times. But apparently I'm not smart enough to figure it out. This works:

      package MyCDBI; use base 'Class::DBI::mysql'; __PACKAGE__->connection('dbi:mysql:mydb', 'me', 'mypwd');

      But this doesn't:

      package MyCDBI; use base 'Class::DBI::mysql'; sub db_Main { use DBI; return DBI->connect('dbi:mysql:mydb', 'me', 'mypwd') or die DBI->errstr; }

      I get the nice error message: Can't locate object "fetch_hash" via package "DBI::st" at Class/DBI/ line 65. The calling script only uses MyCDBI and prints a hello world, so there's nothing from that that's causing this. Any suggestions?

      code('Perl') || die;

        Doesn't db_Main have to return an Ima::DBI compatible handle now, rather then just a plain DBI handle?

        It says so, rather obliquely:

        The preferred method for doing this is to supply your own db_Main() method rather than calling connection(). This method should return a valid database handle, and should ensure it sets the standard attributes described above, preferably by combining $class->_default_attributes() with your own.

        I think the part about a valid database handle is where they mean one derived from Ima::DBI.


        If you scan up right above the Dynamic Database Connections / db_Main heading, it says:

        We use the inherited RootClass of DBIx::ContextualFetch from Ima::DBI, and you should be very careful not to change this unless you know what you're doing!

        Maybe someone with a little more knowledge on this than I can provide a working example?

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://362539]
Approved by tomhukins
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2020-10-20 05:20 GMT
Find Nodes?
    Voting Booth?
    My favourite web site is:

    Results (208 votes). Check out past polls.