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

I have been placed in the precarious position of trying to figure out how to do something and I am not exactly sure how to do it. And I am running this by all of you to see if it is a good idea or not.

I have to write a series of cgi scripts much like the VA hospital ( for talking to them was the concept for my system ) so that rhe system has a core set of data for each user ( address, name, the usual ) and then each department has additional data that relates to that table. If this was a hospital the example would be patient data is the core and the eye doctor would have files that relate to his/her eyes. And each deaptment would be able to relate. And sometimes data would be shared with other departments. Like making sure they don't have 2 surgeries at the same time.

A database makes the organizing of the data in such a way possible. And most of that data in above example is related to the code user data.

What I am asking your opnions on is I need to give the people who are designing each of the departments data in my version an easy way to access the core user data, and update ect it.

I was thinking can an object make it's own database connection? Like when new is called it connected to the database inside the object and suplied the programmer with all the methods they needed to get and edit the data.

Is this a good way of doing in and having all of the shared data resources get their own objects? What do you think and are there any examples of objects making their own database connections through DBI?

Thanks in advance

Replies are listed 'Best First'.
Re: Object DBI concepts
by djantzen (Priest) on Nov 08, 2002 at 01:35 UTC

    Certainly it is possible to embed that code within object initializers. The question is whether there is any pressing need to store the DB connection within an object. In building your object model I would reflect on a few issues:

    1. Do you want to standardize startup/shutdown behavior across multiple scripts/CGIs? Say, a flag for reusing handles during instantiation and autocommit code in the absence of any errors at closing. This could go into the constructor and DESTROY methods, respectively. If not, BEGIN and END blocks will suffice.

    2. Will other code in your CGIs require access to the DB handle? Do you want to have to request a reference from an object, or would it be more handy to store the handle somewhere like $main::db?

    3. How will user access be restricted and monitored? It will be critical to provide a strict programming interface to your table as opposed to allowing your customers direct access to your table via SQL, even if they are trusted parties. You'll probably want something like a 'User' module with accessors, mutators, and a 'save' method. If you decide to head in this direction, you'll almost certainly be better off keeping the DB connection object separate from any logic modules for manipulating table data.

    HTH, fever

      1. Yes that is the reason for attempting this so that each programmer ( they are volunteers ) can just use this object and have the user data at their fingertips and only have to worry about their departments specific data.

      2. Yes it will I was figuring just having the complete DB code inside that object so that if I need to I can edit that bit only and then everyone elses code will still continue to work. I dont understand how keeping the DB access code seperate helps? And how do I pass the db handle as a reference? You would set that upon instantation of the object right?

      The users are interacting via CGI and they can update their data through the cgi inteface. I was figuring a tool for the programmers to use this way we all use the same validation methods on the core user data.

        Okay, so some other programmer will be writing, say, a command line script that requires connection to your DB, and you want them simply to create an object to give them access to your data. I was thinking mostly in terms of requests coming in through a web server.

        One option then is to write a module with a constructor capable of creating the connection, which is in turn instantiated as part of the instantiation of your user data access module. Here's a rough and ready sketch:

        package UserDBConn; sub new { my ($class, $param1, $param2 ...) = @_; my $this = bless({}, $class); # store the returned DB handle in a private slot $this->{_db} = DBI->connect($param1, $param2 ...); } sub getDBHandle { return $_[0]->{_db}; } package User; # lexically scoped at file level so you can create multiple # instances of this module within this process using the # same UserDBConn. Creating a new DB connection each time # you want to pull out a user's information would be *bad*. my $user_db_conn; # = new UserDBConn(...); sub new { my ($class, $username, $more_stuff) = @_; my $this = bless({}, $class); $user_db_conn ||= new UserDBConn(...); # now use $user_db_con->getDBHandle() to populate $this } sub setX {} sub getX {} sub save { # write all our data to the table }

        This approach has the benefit of creating a reusable custom wrapper module around your DBI connection, meaning you can utilize it in other circumstances. Plus you've got the separation of business logic dealing with your user data from the database connection logic. And, your fellow programmers in other departments have no need to know anything about the DB connection under the covers.

Re: Object DBI concepts
by abatkin (Sexton) on Nov 08, 2002 at 06:04 UTC
    From the point of view of readability and maintainability, your plan of putting everything into its own class and having the class query the database sounds great. A couple suggestions/comments however:

    Consider some sort of abstraction for getting a database handle and connecting, something like $dbh = get_db_handle(). This way you can build some sort of system where the first call creates and opens the handle and caches it and then it just gets returned each additional time the function is called.

    The other thing to thing about is whether it will really work well to have everything enapsulated in its own class. For some applications this works well, but for others you may find that you will be needing to build complex queries that might involve data not in that particular class or some sort of complex join or something. (Well, it is almost always possible to do everything you need without doing anything complex and outside the class, but you will sacrafice a great deal of speed, and make the Perl code a lot more complex).

    To figure out how best to model the data with your classes think about this simple example:
    A patients table and a visit table. If you want information about a particular visit of a particular patient, you create a single patient object and a single visit object. Simple enough.
    What do you do if you want all of the visits on a particular day?
    What do you do if you want all of visits belonging to a single patient?
    What do you do if you want to join the two tables and see all patients visits?

    Just something to think about...
      Consider some sort of abstraction for getting a database handle...

      <Shameless plug/>

Re: Object DBI concepts
by princepawn (Parson) on Nov 08, 2002 at 14:56 UTC
    Consider some sort of abstraction for getting a database handle...
    Something like my DBIx::Connect? And for SQL, something like my SQL::Catalog or a bit of DBIx::Recordset.

    My opinion is that your data model should be in your database and only in your database, and you should simply use Perl to drive the database via DBIx::AnyDBD. For a proof in concept of this please my module PApp::Hinduism.

    For the opposing point of view, which seems closer to what you were posting and looking for see Alzabo or Tangram or Class::DBI or SPOPS.