Re: [CDBI] delete from lookup table

[prev] [thread] [next] [Date index for 2005/10/27]

From:
Subject: Re: [CDBI] delete from lookup table
Date: 08:02 on 27 Oct 2005
This is a multi-part message in MIME format.

--===============1154549139==
Content-class: urn:content-classes:message
Content-Type: multipart/alternative;
	boundary="----_=_NextPart_001_01C5DACC.BE3F2593"

This is a multi-part message in MIME format.

------_=_NextPart_001_01C5DACC.BE3F2593
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

> Peter Speltz [peterspeltz@xxxxx.xxx] wrote:
>  What i have seen a lot is  is the use or "delete_all" on the results
>  from a search.
>  $class->search( id =3D> $related_id)->delete_all;

>  and if a "my_method" is a has_many accessor i think you can say;
>  $self->my_method(id =3D> $id)->delete_all;

Unfortunately this does not work - it returns the mapped objects =
themselves. Thus, using
this code you end up deleting both the entry in your lookup table *and* =
the the record for
the mapped object.

>  I'm not sure if has_many method will return an iterator in scalar
>  context or not.

In scalar context it is an iterator, in list context a list of the =
proper objects.


> Bill Moseley [moseley@xxxx.xxx] wrote:
>  The use where I needed something like this is when updating, say, a
>  user form where there's collection of checkboxes for "Roles" which =
are
>  maintained in a many_to_many table.

This is exactly my scenario - the tables (simplified) are:

   table USER with columns 'id', 'name'
   table USER_GROUP_MAP with columns 'user_id', 'group_id'
   table GROUP with columns 'id', 'name'

The method containing the mapping information is called 'mapped_groups'.

The code snippet Bill provided (see below) does the right thing - and I =
did it more or less in the same but a non-generic way by providing an =
extra sub in my USER class. The thing I do not really like about Bill's =
code is the need to dig into the object's hash structure - because there =
is no method available to retrieve the necessary information. I'd rather =
have a somewhat 'cleaner' way of deleting the mapping data.


That said I think it'd be very nice to have something like these =
'add_to_XXX' (in this case:  'add_to_mapped_groups') methods for =
removing the mapping information like:

   $user -> delete_from_mapped_groups(@group_objects_to_be_deleted);

I believe that CDBI should have all the necessary information internally =
to be able to dynamically create something like this? Correct me if I am =
wrong (I have not had a detailed look at the CDBI's internals).

WDL

----------------
Bill's code:

>BTW -- I'm not that clear on what the "mapping" array can hold -- seem
>like it's always a one element array.

>        # here, $class is "User" and $field->name is "roles"
>
>        $meta =3D $class->meta_info('has_many')->{$field->name};
>
>        # Grab the value from the form field
>        my $value =3D $field->value;
>
>        # Figure out which values to keep:
>
>        my %keep =3D map { $_ =3D> 1 } ref $value ? @$value : ( $value =
);
>
>        # Get foreign class and its key that points to $class
>        my $foreign_class =3D $meta->foreign_class;  # Mapping class
>        my $foreign_key   =3D $meta->args->{foreign_key};
>        my $related_key   =3D $meta->args->{mapping}->[0];
>
>        # This limits to using a mapping table.  Hard to imagine an =
interface=20
>        # for adding a has_many without a mapping table, but it could =
be a table
>        # of just columns id, name, f_key, I suppose.
>
>        die "Failed to find related_key for field [$field] in class =
[$class]" unless $related_key;
>
>        # Delete any items that are not to be kept
>
>        for ( $foreign_class->search( { $foreign_key =3D> $item } ) ) {
>            $_->delete unless delete $keep{ $_->$related_key };
>        }
>
>        # Add in new ones
>        $foreign_class->create( {
>            $foreign_key =3D> $item,
>            $related_key =3D> $_,
>        } ) for keys %keep;


------_=_NextPart_001_01C5DACC.BE3F2593
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
charset=3Diso-8859-1">
<META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
6.5.7232.39">
<TITLE>Re: [CDBI] delete from lookup table</TITLE>
</HEAD>
<BODY>
<!-- Converted from text/rtf format -->

<P><FONT SIZE=3D2 FACE=3D"Courier New">&gt; Peter Speltz =
[peterspeltz@xxxxx.xxx] wrote:</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; What i have seen a =
lot is&nbsp; is the use or &quot;delete_all&quot; on the results</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; from a search.</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; $class-&gt;search( id =
=3D&gt; $related_id)-&gt;delete_all;</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; and if a =
&quot;my_method&quot; is a has_many accessor i think you can say;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; =
$self-&gt;my_method(id =3D&gt; $id)-&gt;delete_all;</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">Unfortunately this does not work =
- it returns the mapped objects themselves. Thus, using</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">this code you end up deleting =
both the entry in your lookup table *and* the the record for</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">the mapped object.</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; I'm not sure if =
has_many method will return an iterator in scalar</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; context or =
not.</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">In scalar context it is an =
iterator, in list context a list of the proper objects.</FONT>
</P>
<BR>

<P><FONT SIZE=3D2 FACE=3D"Courier New">&gt; Bill Moseley =
[moseley@xxxx.xxx] wrote:</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; The use where I =
needed something like this is when updating, say, a</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; user form where =
there's collection of checkboxes for &quot;Roles&quot; which are</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;&nbsp; maintained in a =
many_to_many table.</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">This is exactly my scenario - the =
tables (simplified) are:</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">&nbsp;&nbsp; table USER with =
columns 'id', 'name'</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&nbsp;&nbsp; table =
USER_GROUP_MAP with columns 'user_id', 'group_id'</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&nbsp;&nbsp; table GROUP with =
columns 'id', 'name'</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">The method containing the mapping =
information is called 'mapped_groups'.</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">The code snippet Bill provided =
(see below) does the right thing - and I did it more or less in the same =
but a non-generic way by providing an extra sub in my USER class. The =
thing I do not really like about Bill's code is the need to dig into the =
object's hash structure - because there is no method available to =
retrieve the necessary information. I'd rather have a somewhat 'cleaner' =
way of deleting the mapping data.</FONT></P>
<BR>

<P><FONT SIZE=3D2 FACE=3D"Courier New">That said I think it'd be very =
nice to have something like these 'add_to_XXX' (in this case:&nbsp; =
'add_to_mapped_groups') methods for removing the mapping information =
like:</FONT></P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">&nbsp;&nbsp; $user -&gt; =
delete_from_mapped_groups(@group_objects_to_be_deleted);</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">I believe that CDBI should have =
all the necessary information internally to be able to dynamically =
create something like this? Correct me if I am wrong (I have not had a =
detailed look at the CDBI's internals).</FONT></P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">WDL</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">----------------</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">Bill's code:</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier New">&gt;BTW -- I'm not that clear on =
what the &quot;mapping&quot; array can hold -- seem</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;like it's always a one =
element array.</FONT>
</P>

<P><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # here, $class is =
&quot;User&quot; and $field-&gt;name is &quot;roles&quot;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $meta =3D =
$class-&gt;meta_info('has_many')-&gt;{$field-&gt;name};</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Grab the value =
from the form field</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; my $value =3D =
$field-&gt;value;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Figure out which =
values to keep:</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; my %keep =3D map { =
$_ =3D&gt; 1 } ref $value ? @$value : ( $value );</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Get foreign class =
and its key that points to $class</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; my $foreign_class =
=3D $meta-&gt;foreign_class;&nbsp; # Mapping class</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; my =
$foreign_key&nbsp;&nbsp; =3D $meta-&gt;args-&gt;{foreign_key};</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; my =
$related_key&nbsp;&nbsp; =3D =
$meta-&gt;args-&gt;{mapping}-&gt;[0];</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # This limits to =
using a mapping table.&nbsp; Hard to imagine an interface </FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # for adding a =
has_many without a mapping table, but it could be a table</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # of just columns =
id, name, f_key, I suppose.</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; die &quot;Failed to =
find related_key for field [$field] in class [$class]&quot; unless =
$related_key;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Delete any items =
that are not to be kept</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for ( =
$foreign_class-&gt;search( { $foreign_key =3D&gt; $item } ) ) {</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; $_-&gt;delete unless delete $keep{ $_-&gt;$related_key };</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier New">&gt;</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Add in new =
ones</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
$foreign_class-&gt;create( {</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; $foreign_key =3D&gt; $item,</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; $related_key =3D&gt; $_,</FONT>

<BR><FONT SIZE=3D2 FACE=3D"Courier =
New">&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } ) for keys =
%keep;</FONT>
</P>

</BODY>
</HTML>
------_=_NextPart_001_01C5DACC.BE3F2593--


--===============1154549139==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
ClassDBI mailing list
ClassDBI@xxxxx.xxxxxxxxxxxxxxxx.xxx
http://lists.digitalcraftsmen.net/mailman/listinfo/classdbi

--===============1154549139==--

Re: [CDBI] delete from lookup table
Peter Speltz 19:27 on 26 Oct 2005

Re: [CDBI] delete from lookup table
Bill Moseley 20:47 on 26 Oct 2005

Re: [CDBI] delete from lookup table
08:02 on 27 Oct 2005

Re: [CDBI] delete from lookup table
Peter Speltz 09:22 on 27 Oct 2005

Re: [CDBI] delete from lookup table
Bill Moseley 12:44 on 27 Oct 2005

Generated at 14:18 on 27 Oct 2005 by mariachi v0.52