| 
      
      
      From: Chris W. <ch...@cw...> - 2001-11-01 22:28:01
      
     | 
| So after thinking about this problem of multiple-field primary keys
for a while, I came up with what seems to be a decent solution. I'm
still testing it out, but it seems to work well and I wanted to see if
anyone had any thoughts before I charged ahead.
First, I believe that the ID of an object should be a string or easily
stringified. This is not only for us people who like to read such
things, but SPOPS does a lot of work (security, for one) using the
object class and ID value. (Caching will be the same way.)
So with that in mind, here's some demo code:
 # This object uses three fields (field1, field2, field3) for the key,
 # and we delimit the values with commas to make a single string. We
 # will probably make the delimiter customizable.
 my $id = join( ',', $field1, $field2, $field3 );
 my $obj = My::MultiFieldKey->fetch( $id );
 # Retrieve the ID in scalar context:
 
 print "ID: (", scalar $obj->id, ")";
 # >> ID: (45,99,ABCD)
 # Now retrieve the ID in list context
 my @val = $obj->id;
 # Values: $val[0] = 45; $val[1] = 99; $val[2] = 'ABCD';
 # Display the SQL clause we use to uniquely retrieve, update and
 # remove this record
 print "WHERE ", $obj->id_clause;
 # >> WHERE table.field1 = 45 AND table.field2 = 99 AND \
 #    table.field3 = 'ABCD'
 # Get the ID fields in scalar context
 print "ID fields for object: ", scalar $obj->id_field, "\n";
 # >> field1,field2,field3
 # Get the ID fields in list context
 my @to_select = map { "$table.$_" }, @selected, $obj->id_field;
What you need to do:
 - Specify the ID fields you want in your object configuration as an
arrayref instead of a string:
  id_field => [ 'field1', 'field2', 'field3' ]
That's it! 
Caveats:
 - You must always keep the ordering of the fields listed in
 'id_field' of your configuration, or you'll break security and other
 object layers (full-text indexing, etc.).
 - You can link to objects in this class, but you can't use the
 'has_a' type of relationship
 - I need to look at and modify something in the lazy loading
 implementation for SPOPS::DBI
 - If part of your multifield key is automatically generated (using a
 pre/post_id method such as with auto-increment/sequenced fields),
 then there *might* be some issues, but it will probably work fine.
How it works:
Two new class-factory behaviors in SPOPS::DBI treat an arrayref in the
'id_field' of a class configuration as a signal to generate the
methods:
  id_field()
  id()
  id_clause()
These are created at startup for a multiple field class, and then it's
just like every other class. There are no modifications to the class
hierarchy or anything else. (And classes using a single field for an
ID aren't touched.)
So I need to test this out some more and see how it works -- nothing
like testing on live data! -- but if you have any ideas I'd love to
hear them. I feel like there's something I'm missing....
Chris
-- 
Chris Winters (ch...@cw...)
Building enterprise-capable snack solutions since 1988.
 |