Hibernate annotations: Many-to-many with shared composite key attribute

waxwing :

I'm trying to map up an existing database schema using Hibernate+JPA annotations.

One of my entities are mapped like this:

@Entity
@Table(name = "users")
public class User implements Serializable {

    @Id
    private int department;

    @Id
    private int userId;

    ...

And another entity, Group:

@Entity
@Table(name = "groups")
public class Group implements Serializable {

    @Id
    private int department;

    @Id
    private int groupId;

    ...

Group and User should have a many-to-many relationship between them, but the issue is that the join table ("user_group") only has columns "DEPARTMENT, USERID, GROUPID" - i.e. the DEPARTMENT column needs to be used in both joinColumns and inverseJoinColumns:

    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(
        name = "user_groups",
        joinColumns = { @JoinColumn(name = "department"), @JoinColumn(name = "groupid") },
        inverseJoinColumns = {@JoinColumn(name = "department"), @JoinColumn(name = "userid") }
    )
    private List<User> groupUsers = new ArrayList<>();

which gives a mapping error - "Repeated column in mapping for entity".

However, it looks like this was/is possible using XML, because this exact example exists in the old Hibernate documentation. But I cannot find any evidence that this ever worked using annotations? I tried with @JoinFormula instead of @JoinColumn, but that does not compile. Is it possible?

waxwing :

Okay, I'm pretty sure it's not possible.

I found a promising workaround:

Create an @Embeddable for the "user_group" table:


@Embeddable
public class UserGroupMembership implements Serializable {

    @ManyToOne
    @JoinColumnsOrFormulas(
        value = {
            @JoinColumnOrFormula(column = @JoinColumn(referencedColumnName = "userid", name = "userid")),
            @JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "department", value = "department"))
        })
    private User user;

    public UserGroupMembership(User user) {
        this.user = user;
    }

    public UserGroupMembership() {
    }

    public User getUser() {
        return user;
    }
}

The trick is that @ManyToOne allows you to use @JoinColumnsOrFormulas, so one of the join conditions can be a formula, which I doesn't seem to work for @ManyToMany (the @JoinColumnsOrFormulas annotation is ignored as it expects the join columns to be part of the @JoinTable annotation).

The UserGroupMemberships are then mapped as a ElementCollection:

    @ElementCollection
    @CollectionTable(name = "user_group", joinColumns = {
        @JoinColumn(name = "department", referencedColumnName = "department"),
        @JoinColumn(name = "groupid", referencedColumnName = "groupid")
    })
    @OrderColumn(name = "seq", nullable = false)
    private List<UserGroupMemberships> groupUsers = new ArrayList<>();

This only works right now for a unidirectional many-to-many relationship.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=356928&siteId=1