On Tuesday 01 July 2008, Pardee, Roy wrote:
But if you’ve got a unique key constraint on the natural key, then
there can’t be > 1 record in your table w/the same values of your
natural key columns. In which case the synthetic key is identity
enough, isn’t it?
What already is in the table is not the problem at all. The problem
occurs when I try to update the table via an association. In that
case, when a new record, i.e. one without an id, has the same attribute
values as an already existing record, the existing record should not be
This is relevant when editing all associated in a single form. Consider
my original example again.
- compiler c running on host OS h can compile for target OS t
- find all compilers that run on host OS h and compile for target OS t
- find all compilers that match some other condition and run on host OS
I have a single form where for a given compiler all host-target mappings
can be edited. Compiler has_many HostTargetMappings; when this
association is updated, it is not possible to simply delete all
associated objects and insert new ones. This approach is bound to
vioate foreign key constraints imposed by other objects associated to
the relevant HostTargetMappings.
AR in principle does the right thing, on host_target_mappings#replace it
inserts new objects, deletes the ones no longer pertinent, and should
leave the others untouched. However, this latter part depends on the
identity of an object being tied to its synthetic id, because #replace
does the comparison using #==, which in turn compares AR objects based
on their id.
Now, imagine if you will, that the user creates a mapping duplicating
the attributes of an already present one. Such a duplicate ought simply
to be ignored, but when comparison is based on id, this object is
unlike any existing one, therefore AR tries to insert it, but fails due
to the foreign key violation.
As I’ve explained at least three times already, the way around this is
to override HostTargetMapping#== so that it is based on attribute
values not id. This works perfectly in my case, but I can’t guarantee
that it won’t blow up because some part of AR might depend on #==
depending on the id.