Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Removing from @ManyToMany collection doesn't work when JoinTable is joined by natural-keys (not PK)

Hi all, I have the following ManyToMany which fails to remove an entry in the join-table when an element in the list is removed:
 
I have a user, with natural key userName (unique) and each user can be member of several groups. Group has the natural-key groupName, and the join-table joins on their natural-keys.
 
The join-table is like this:
 
 groupname | character varying | not null
 username  | character varying | not null
Indexes:
    "onp_user_group_pkey" PRIMARY KEY, btree (groupname, username)
    "onp_user_group_gropuname_idx" btree (groupname)
    "onp_user_group_username_idx" btree (username)
Foreign-key constraints:
    "$1" FOREIGN KEY (groupname) REFERENCES onp_group(groupname) ON UPDATE CASCADE ON DELETE CASCADE
    "$2" FOREIGN KEY (username) REFERENCES onp_user(username) ON UPDATE CASCADE ON DELETE CASCADE
 
 
The entities, User and Group, are defined as:
 
@Entity
@Table(name = "onp_user")
@PrimaryKeyJoinColumn(name = "id")
@DiscriminatorValue("USER")
class User
 
    @Id
    @Column(name = "id", nullable = false)
    Long id;
 
    @Column(name = "username", unique = true, nullable = false)
    String userName
...
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "onp_user_group",
        joinColumns = {@JoinColumn(name = "username", referencedColumnName = "username")},
        inverseJoinColumns = {@JoinColumn(name = "groupname", referencedColumnName = "groupname")}
        )
        List<Group> groups;
 
 
 
@Entity
@Table(name = "onp_group")
@PrimaryKeyJoinColumn(name = "id")
@DiscriminatorValue("GROUP")
class Group
 
    @Id
    @Column(name = "id", nullable = false)
    Long id;
 
    @Column(name = "groupname", unique = true, nullable = false)
    String name;
 
 
 
The problem is that when removing an entry in user.groups, then the entry is not removed from the join-table "onp_user_group", because the query EL ends up executing is:
LOG:  execute cached-531203064: DELETE FROM onp_user_group WHERE ((groupname = $1) AND (username = $2))
DETAIL:  parameters: $1 = 'Somegroup', $2 = NULL
 
So NULL is passed as the value for "userName".
 
I see in the method (EL-source) CollectionMapping.writeChanges that the WriteObjectQuery passed as an argument (with argument-name "query") has a property "translationRow" which is used to map keys, and this Map contains the following when trying to persist changes:
 
onp_user.id=134
 
But RelationTableMechanism.addRelationTableSourceRow has the value "onp_user.username" in its sourceKeyFields, which doesn't map to an entry in the passed sourceRow. This results in the addRelationTableSourceRow method adding NULL as a value to key="onp_user.username", because sourceValue is assigned the value NULL:
 
    public AbstractRecord addRelationTableSourceRow(AbstractRecord sourceRow, AbstractRecord databaseRow) {
        int size = sourceKeyFields.size();
        for(int i=0; i < size; i++) {
            Object sourceValue = sourceRow.get(sourceKeyFields.get(i));
            databaseRow.put(sourceRelationKeyFields.get(i), sourceValue);
        }
        return databaseRow;
    }
 
So, is there a way to make this work, or do I have to use primary keys in the join-table? Everything else works nicely, just not removing.
 
Thanks.
 
--
Andreas Joseph Krogh
CTO / Partner - Visena AS
Mobile: +47 909 56 963

Back to the top