On 11/7/06, Jud Dagnall <[EMAIL PROTECTED]> wrote:
> In my application, there is are projects, tags, and profiles (users).
> Projects can be tagged by multiple profiles. Each tag has a many-to-many
> relationship both projects and profiles. There's a mapping table
> (tag_project_profile_map) with a 3-column primary key that relates those
> three tables.
> [...]
> I'd like to be able to add tags to a project as follows (specifying the
> missing primary key value):
>
> $project->tags( { name = 'cool_stuff', profile_id => 1 } );
> $project->save;
>
> However, this gives me an error because the 'tags' table doesn't
> actually have a profile_id, only the mapping table does.

There are a few possible ways to go about this.  One is the manual
way, where you actually instantiate and them modify the map record
separately, as shown here:

> my $mapping = TagProjectProfileMap->new(
>         {project_id => 1,
>           tag_id => 2,
>           profile_id => 3});
> $mapping->save;

(Although the argument to new() should not be a hashref.)

Another way is to set the tags, use the Manager to re-fetch them,
modify the map records, and then re-save them:

    $project->new(id => 1)->load;
    $project->tags(...);
    $project->save;

    $project =
      Project::Manager->get_prouducts(
        with_objects => [ 'tags' ],
        with_map_records => 1,
        query => [ id => 1 ])->[0];

    foreach my $tag ($project->tags)
    {
      $tag->map_record->profile_id(...);
      $tag->map_record->save;
    }

That's a save(), load(), and then re-save() for each map record, however.

The next method I can think of is to split up your single mapping
table into two mapping tables, e.g.. project_tag_map table and a
project_profile_map.  Then you could just do:

    $project->tags(...);
    $project->profiles(...);
    $project->save;

Maybe that's not exactly in keeping with what you're trying to model,
but the three-way tag_project_profile_map mapping table is a bit odd.
The concept of a map table in RDBO is supposed to be part of a
many-to-many relationship between two classes, not three.  As you've
discovered, it'll pretty much still work with three, but there's a bit
of a mismatch in intent.

Finally, you could forego the many-to-many relationship definition and
instead (or "also") defined it as chain of relationships that
explicitly includes the mapping table:

             Project
                |
           one to many        <- rel name: tag_profile_map_records
                |
                v
        TagProjectProfileMap
          /            \
     foreign key    foreign key
        /                \
       v                  v
      Tag               Profile

Then do:

    $project->new(id => 1)->load;

    $project->tag_profile_map_records
    (
      {
        tag     => { name => 'foo', ... },
        profile => { username => 'bar', ... },
      },
      {
        tag     => { name => 'baz', ... },
        profile => { username => 'blee', ... },
       },
       ...
    );

    $project->save;

> I looked at trying define a custom primary_key_generator() function in
> my TagProjectProfileMap, but I didn't see that I could get the
> additional parameters.

A pk generator is definitely not the right approach to this problem.

-John

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Rose-db-object mailing list
Rose-db-object@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rose-db-object

Reply via email to