Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Class::DBI not intuitive

by Jaap (Curate)
on Jul 26, 2004 at 20:06 UTC ( #377549=perlmeditation: print w/ replies, xml ) Need Help??

Either there is something wrong with me (probably is), or with Class::DBI.

Why are there retrieve, retrieve_all, search and search_like methods that all do kinda the same thing?
Also, why does it invent add_to_cds functions when add_to(cds) or {cds}->add_to or something would me much more logical (at least to me)?
I also dont quite get how sometimes i need to call retrieve, and sometimes i don't, like so:
my $cd = Music::CD->retrieve(1); my $year = $cd->year;
I am still retrieving the year am i not?

Anyone else's brain works (un)like mine?

Comment on Class::DBI not intuitive
Download Code
Re: Class::DBI not intuitive
by itub (Priest) on Jul 26, 2004 at 20:56 UTC
    my $cd = Music::CD->retrieve(1); Retrieve a row (as an object) from the database. Note that this is called as a class method.

    my $year = $cd->year; Get a column (a field) from an object. Note that this is called as an instance method, on the particular object retrieved above.

    search and search_like are different in that search_like uses the SQL LIKE operator, which allows wildcards. They differ from retrieve in that retrieve only selects based on the primary key, whereas search can use any column or columns. And I think the difference between retrieve and retrieve_all should be obvious just by looking at the name.

      "And I think the difference between retrieve and retrieve_all should be obvious just by looking at the name."

      itub's explanation was very lucid, and I just want to elaborate a little bit on the quoted comment of his.

      Other than the obvious difference implicated by the naming, the real concern is performance. It would be quite unwise to do a retrieve_all, when you only care about couple of rows. Indeed the underlying data system might support batch fetch, for example Oracle, this provides the opportunity to fully utilize this and similar kind of functionalities, in the actual implementation, to gain the best performance.

        "... this provides the opportunity to fully utilize this and similar kind of functionalities, in the actual implementation, to gain the best performance."

        Does anyone know if Class::DBI actually does this? (Uses optimal implementation-specific functionality, for example in Oracle?)

        I read perldoc Class::DBI and the explanation for retreive_all doesn't say whether it does so. One of the reasons I have avoided Class::DBI is I worry its SQL must be heavily suboptimal to facilitate operation on everything from SQLite to Oracle. I remember reading a comment on PM from someone who was monitoring Class::DBI SQL queries in real time and reported being mildly horrified (I have never been able to find the post).

Re: Class::DBI not intuitive
by hardburn (Abbot) on Jul 26, 2004 at 21:07 UTC

    I am still retrieving the year am i not?

    Yes. What's your point? In CDBI, the class represents a complete table, and the object you get back from Class::DBI->retrieve() represents a single row in the database. You can also get a list of objects back from Class::DBI->search() or retrieve_all(). Or you can call either in scalar context and get an iterator that let's you go through the objects, if you like that sort of thing.

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

Re: Class::DBI not intuitive
by naChoZ (Curate) on Jul 26, 2004 at 22:14 UTC

    I found it fairly confusing myself. Although it doesn't have a whole lot to do with the learning curve, one thing that's a great step in simplifying things is Class::DBI::Loader. It automates most of the class setup and initialization tedium.

    --
    "A long habit of not thinking a thing wrong, gives it a superficial appearance of being right." -- Thomas Paine
    naChoZ

Re: Class::DBI not intuitive
by perrin (Chancellor) on Jul 27, 2004 at 00:15 UTC
    Sounds like you are looking for an easy DBI tool. Class::DBI is an object/relational mapper, intended to let you manipulate your data as objects. It is not as simple as other tools that are just trying to give you DBI shortcuts.
Re: Class::DBI not intuitive
by Joost (Canon) on Jul 27, 2004 at 00:58 UTC
    Class::DBI provides a mapping between a relational database and a class/object system. However unintuitive the API may seem, most of it is fairly obvious if you consider table =~ class, row =~ object, column =~ property, and the different ways of retrieving data via SQL. The more problematic parts are caused by the numerous mismatches between perl and SQL that are impossible to solve efficiently without explicit programmer input. Hence for example the explicit difference between search() and search_like().

    I personally find the Class::DBI API one of the more straightforward implementations of an object-relational mapping I've used, plus it's reasonably efficient.

    If you really think it is confusing, I suspect you might benefit from reading up on SQL or OO programming. Or try to make such a system yourself. I did, and I learned a lot. One of the things I learned, was that writing your own database abstraction layer is a lot harder than it looks. :-) I switched to Class::DBI for everything except code that really needs the performance of the "raw" DBI.

Re: Class::DBI not intuitive
by dragonchild (Archbishop) on Jul 27, 2004 at 02:18 UTC
    CDBI is an example of an object-relational mapping system. One thing you may be stumbling over is that this is most definitely not the best solution in many cases. (In fact, some may say that object-relational mapping is usually a good indication your database is poorly designed, but that's another discussion. Google Fabian Pascal for more info.)

    Many applications instead require a business concept to relational mapping, where you have database accessors that provide business-model API calls, regardless of the underlying architecture. CDBI is not intended to solve this problem. In fact, using it in this case would cause you nothing but headaches trying to fit a perfectly good square peg into a round hole.

    That said, CDBI is very good when it's used where it's meant to be used. A lot of smaller applications can decompose their data into a class-to-table relational structure. This isn't to say that CDBI is only useful for smaller applications. It's just that most of the examples I've seen where CDBI really shines are for smaller things like picture albums and CDDB-type MP3 lookups. I'm sure there are a lot of larger enterprise-level apps that are perfectly happy using CDBI for their RDBMS access.

    I've never worked on an app that would have benefitted from it, but I also tend to work on apps that do a lot of custom reporting. While CDBI would help the development effort, I also have a lot of performance constraints that CDBI would miss unless I threw a ton of hardware at it. In my current app, for example, every single report (with a few exceptions) has to run in under 5 seconds, no matter what load or what the SQL looks like. Period. CDBI has too much overhead and innefficiency built in to be useful there, even if the syntactic sugar would be nice.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      While quite true that there is a performance compromise with CDBI, it can shave a week off of the development of a one-man project easily. I absolutely love it and would be lost (well, deeper into carpal tunnel country) without it. The regular and thoughtful indexing and optimization of the underlying DB can help make up for some of trade-off too.

      This is a node that has really touched on the issues that have made me disinclined to go down the CDBI route. But i have to admit i'd really like to hear you summarize this more cogently. I did do a search on Fabian Pascal but I think an article on the subject by yourself would be a very worthy meditation.

      All I can say is that every time ive looked into CDBI it seems appropriate for fairly naive DB's but for serious work it seems totally unsuitable for handling complex relationships and business logic. Your comment about object/record class/table mappings really seems to encapsulate the problems I have. Its extremely unusal for me to have any such mapping, in fact its much more common to have objects be represented as a derived amalgamation of many records from many tables.

      Anyway, I really hope you meditate on this.


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


      I very much agree with you that OO->Relational mapping tend to work much better for small applications where performance is not critical. But that is not to say that it cannot be used within larger more performance critical applications. We tend to use our own Object Persistence/OO->Relational tools for things like the user-administration portion of our reporting applications where performance is not critical, while using optimized SQL/DBI code for the reports themselves. It greatly simplifies the code in the user-admin portion of the site and makes it much easier to maintain, which works out well cost-wise too since that portion of the site it not really what our customers care about.

      A lot of smaller applications can decompose their data into a class-to-table relational structure.

      One misconception about OO->Relational mapping tools is that they are bound to class-to-table relationships. This may be true of Class::DBI (I don't know I have never used it), but the more generalized OO->Relational mapping patterns are not confined to that basic a relationship. Simple tools will map table-column to class-field, and this is only so useful. A more complex tool (or possibly custom written code) could use a longer more complex query with multiple table joins to return a result set which can then be mapped into an object. So now your class-fields map to columns in multiple tables. Of course this gets much more complicated with INSERTs, UPDATEs and DELETEs. This may require a lot of up-front work, but IMO that is the right kind of laziness.

      I recently picked up a book called Patterns of Enterprise Application Architecture by Martin Fowler. It's examples are mostly in Java or C#, but the patterns themselves are language agnostic. It has a number of patterns dealing with OO->Relational mapping, you might want to check it out, very interesting stuff.

      -stvn
        A more complex tool (or possibly custom written code) could use a longer more complex query with multiple table joins to return a result set which can then be mapped into an object. So now your class-fields map to columns in multiple tables.

        This may be a dumb question, but how is this different from the business object mapping that I referred to?

        The benefits of CDBI and similar tools (like Hibernate for Java) is that they do a lot of work for you, but the tradeoff is that the work is generally mediocre. In the places where mediocre is good enough, then it would be foolish to do that work by hand. (The other app in my office uses Hibernate, specifically for that reason.)

        But, in those places where you need to write custom code to map your objects (which are presumably business-oriented) to the database (which is presumably storage-oriented), you don't have an OO->Relational tools gain.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

        I shouldn't have to say this, but any code, unless otherwise stated, is untested

Re: Class::DBI not intuitive
by astroboy (Chaplain) on Jul 28, 2004 at 01:24 UTC

    Lots of modules seem to have lots of methods for (sort of) doing the same thing, but you get used to them. If I haven't used DBI for a while, I sometimes forget the differences between selectrow_array, selectrow_arrayref, selectrow_hashref, selectall_arrayref, selectall_hashref, selectcol_arrayref etc - and these are just the methods for the database handles - there are the statement ones too. There are so many ways to get at the data you want! The method names are descriptive enough, but I often forget what parameters they all expect, etc. But a quick lookup of the doco sets me on my way.

    I've only played with Class:DBI in passing, but I like what I've seen...

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://377549]
Approved by gmax
Front-paged by Enlil
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (7)
As of 2014-10-01 23:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    What is your favourite meta-syntactic variable name?














    Results (41 votes), past polls