Hi Jess,
I'm quite willing to give back to the project in terms of editing documentation
but thought this might be limited to editing, because it should be written from
the perspective of someone who knows the "right" way to use the system or its
core philosophy.
I can't reply at length now since it is 1AM but will think about it some more.
For a quick reply, yes I've read that page, the cookbook page,
Relationships::Base, page, etc. and a number of times. But to me anyway it
seems to assume a lot of knowledge, skips describing the foundation of what the
module is intended to do, and skimps on the important parts. In order to get a
feeling of which method to pick and how to practically use it you basically
have to read many different documents over and over, pulling information in
about other methods, and finally of course already know a lot of about what is
really going on in the database. To me the module ought to be shielding you
from having to think about it so much but that probably isn't realistic. To
illustrate a couple points come to mind:
The very helpful replies I received about "insane layout" (i.e. having an id in
both tables pointing to each other), it is not obvious to even someone who has
used databases and perl a lot for small systems it isn't sane. Of course if the
two relationships get out of sync then you might get different data depending
on which table you start from, hence the insanity. But very little info on
designing ORM based systems with lots of objects and relationships.
Also no information about Relationships and foreign relations. In fact I had
been under the impression at least that mysql3 couldn't do foreign relations,
and I'd decided to do it all using DBIx Relationships instead. The notion of
foreign keys in the db being useful for maintaining integrity of data is not
mentioned; it seems that a Relationship would do something like this but of
course it isn't the same.
Also check out this part of the FAQ you mention, it is quite confusing actually.
"Relationships
... define a foreign key relationship where the key field may contain NULL?
Just create a belongs_to relationship, as above. If the column is NULL then the
inflation to the foreign object will not happen"
Now according to Matt's very helpful notes in the ML, allowing NULL in your db
schema is used to tell belongs_to to be an optional Relationship, meaning that
it will not enforce the belongs_to rule and autovivify. In other words use NULL
so DBIx::Class::Relationships does not do inserts when it thinks that would be
"the right thing". (or you can make a dummy record, but that's painful I found).
But the above passage comes from the other direction, assuming first that the
developer wants to allow a NULL, and then explains that allowing NULL will
disable object inflation (which I did not know until I just checked now!). It
doesn't say that it disables autovivification, even though anything that does
an INSERT is to me a potentially naughty thing and deserves to be
well-documented.
Now we go back to the perldoc for the belongs_to method does not mention that
object inflation will be disabled, rather saying "If the relationship is
optional -- i.e. the column containing the foreign key can be NULL -- then the
belongs_to relationship does the right thing. Thus, in the example above
$obj->author would return undef. However in this case you would probably want
to set the join_type attribute so that a LEFT JOIN is done, which makes complex
resultsets involving join or prefetch operations work correctly. "
This does not explain whether object inflation being "disabled" just means
returning an undef if it's a NULL (which of course would be intuititive) or
whether it means something like $listing->coupon will not return an object in
any case if the field in question allows NULL. It also does not explain about
from which side to make a Relationship (or both sides - no that's insane
apparently, despite being logical in English anyway), though it is mentioned in
the FAQ (regarding one-to-many) that "Currently these need to be set up
individually on each side."
Also the pod mentions left joins and right joins. As I understand it a normal
join would only provide records that match across the two tables but a left
join would also show items not matched in the left table, and similarly right
would for the right table. But this is not explained, and it is not clear why
an ORM would not handle this sort of thing for you, or how the left/right sql
metaphor for tables translates into parent object -> child object metaphor of
DBIx::Class.
Something about usage of foreign relations in the db for integrity control
would be helpful, and would explain the difference between what
DBIx::Class::Relationships offers and what the db offers.
I think it would be quite helpful if a design example similar to what I had
posted is used (you can use my objects if you want). For one thing there is
confusion among people who want to use an object oriented system but then have
to build an sql table schema to fit it. They start thinking in an object
oriented fashion. Then they have to translate it into tables in their head
(probably writing sql create statement by hand or with a tool like phpmyadmin,
though maybe they really should use DbDesigner, or maybe they should just stay
away from mysql and go to postresql). Anyway once they have the tables they
start using DBIx::Class and it seems to work nicely, except it fails sometimes,
and they end up having to figure out the more esoteric parts of the module
which are not as well documented. I think this tends to lead to spaghetti
objects, insane layout, and fragile schemas.
Well this turned out to be a long post. Sorry, and no offense meant at all,
just that I'm willing to contribute to documentation in thanks for your
support. So this is in response to how a non-dba person might see the module.
I've used DBI and CDBI, etc. with Perl for many years but don't make my living
as a database designer, and haven't needed to get high end database performance
(my high performance mod_perl systems have used a Perl embedded db or a C++
based system).
Anyway to try and wrap up this unending post, I would just mention that the
DBIx::Class docs spend a lot of time talking about how you can agilely use lots
of different chained methods to search or insert in related tables and so on,
but spend very little time talking about what this actually does in the db,
what the actual db schema is, whether something is available in mysql or
another db or not, etc. For example I don't think I saw anything about
sequences. I don't think foreign keys or null values were mentioned in the
Artist/CD applications. Nothing about what "doing the right thing" could mean
or how to design an application starting with a Perl (DBIx::Class) design and
then what kind of tables you should make for those objects. I think this sort
of thing might be useful.
Also I find a lot of my code tends to be paranoid. I test the results of all db
updates and capture errors, displaying an error message and halting when
processing hits an error. So I tend in my Catalyst app to first get required
input arguments, test them (or die with a pretty error page to browser), then
look up chained object info, testing whether the next link in the chain
actually returns me an object or not and dying prettily each time if it
doesn't. Finally I know I have good data and do the processing and output a
template.
This is probably way too much code. For one thing a lot of this should be
covered probably by integrity assurances in the db, at least that is my
interpretation of a "sane layout". Though probably not to be expected if my
client is editing the db manually. Also a lot of that should be done in Model
modules, I'd expect, certainly it isn't DRY since I do it over and over. And
I'd like to be able to look up a bunch of stuff with DBIx::Class and then check
to see if any errors occurred, as one might with eval and $@, instead of doing
so many tests, just to reduce the amount of code but maybe that isn't a great
idea. So I admit the last app had just about all code in the controller modules
and just schema and relationship creation lines in the model modules. This is
not what the Catalyst people seem to like (since it makes it hard to access the
system from command line or other interface than ordinary html browser) but it
does seem to be what the cookbooks offer. So great
volumes of extremely sane, DRY, smart layouts and uses of DBIx::Class and
especially in a Catalyst environment would be quite useful to the world I
think. This might require the developers of Catalyst and DBIx::Class to put
their heads together but to me the more robust the better and if that can be
done with less code and more extensibility to other interfaces then best yet.
Also for what it's worth, I found both startling, amazing, cool, mysterious and
scary that I could access chained objects (in dot notation) from within a TT2
template that are not provided from the calling Perl subroutine, without any
attributes specified, and that such a call could even cause INSERTS in my db
from just trying to view what I'd planned as a read-only page in the browser
(due to auto-vivification). Also if objects aren't available (I suppose if
NULL, or if the id does not have a corresponding row in the other table) TT2
will crash I think, so you have to use TT2's defined keywords to try to sneak
up on them, and sometimes that won't work it seems. So while this is a Catalyst
and TT2 issue I think you might want to add something about this, and what
actually is going on (what kind of a search is being made) when you call an
object in TT2. (I'm talking about the case in which your TT2 template is
displaying a list of "listing" objects, and if "r" is a single
listing, you type "r.customer.b_company" to try and get the company name of
the customer that owns the listing.)
Well I don't provide these as criticism, so much as trying to describe how the
module looks to someone who does not have the same background as the developer.
I hope you take it with a grain of salt too since it is more a measure of my
own usage of it and lack of knowledge than as an imperative that you must do
something about it!).
Thanks again and if you wish I would be happy to contribute or edit docs.
Again, also I would like to thank Matthew Trout for his fabulous comments and
help.
Matt Rosin
____________________________________________________________________________________
Moody friends. Drama queens. Your life? Nope! - their life, your story. Play
Sims Stories at Yahoo! Games.
http://sims.yahoo.com/
_______________________________________________
List: http://lists.rawmode.org/cgi-bin/mailman/listinfo/dbix-class
Wiki: http://dbix-class.shadowcatsystems.co.uk/
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/trunk/DBIx-Class/
Searchable Archive: http://www.mail-archive.com/[email protected]/