通过共享属性的复合键来休眠@ManyToMany关系

时间:2018-07-05 22:02:43

标签: java hibernate jpa

因此,我正在使用使用许多复合键的数据库。我正在尝试使用JPA /休眠来为一种关系建立一个JoinTable。这是正在做的精简示例

家长班

@Entity
@Table(name = "PROTAGONIST")
public class Protagonist {
    private Integer id;
    private String name;

    @Id
    @Column(name = "id", nullable = false)
    public Integer getId() {return id;}

    public void setId(Integer id) { this.id = id;}

    @Column(name = "pro_name", nullable = false, length = 50)
    public String getName() {return name;}

    public void setName(String name) { this.name = name;}
}

商品ID类别

@Embeddable
public class ItemId {
    private int pId;
    private short invSlot;

    @Column(name = "P_Id", nullable = false)
    public int getpId() {return pId;}

    public void setpId(int pId) { this.pId = pId;}

    @Column(name = "Inv_SlotNum", nullable = false)
    public short getInvSlot() {return invSlot;}

    public void setInvSlot(short invSlot) { this.invSlot = invSlot;}
}

物品类

public class Item {
    private ItemId id;
    private String itemName;
    private Double cost;
    private Set<Buff> buffs;

    @EmbeddedId
    public ItemId getId() {return id;}

    public void setId(ItemId id) { this.id = id;}

    @Column(name = "Item_Name", nullable = false, length = 100)
    public String getItemName() {return itemName;}

    public void setItemName(String name) { this.itemName = name;}

    @Column(name = "Item_Cost")
    public Double getCost() {return cost;}

    public void setCost(Double cost) { this.cost = cost;}

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "BUFFSONITEMS",
        joinColumns = {
            @JoinColumn(name = "P_Id", referencedColumnName = "P_Id"),
            @JoinColumn(name = "Inv_SlotNum", referencedColumnName = "Inv_SlotNum")
        },
        inverseJoinColumns = {
            @JoinColumn(name = "P_Id", referencedColumnName = "P_Id"),
            @JoinColumn(name = "Buff_SlotNum", referencedColumnName = "Buff_SlotNum")
        }
    )
    public Set<Buff> getBuffs() {return buffs;}

    public void setBuffs(Set<Buff> buffs) { this.buffs = buffs;}
}

Buff ID类别

@Embeddable
public class BuffId {
    private Integer pId;
    private Short buffSlotNum;

    @Column(name = "P_Id", nullable = false)
    public Integer getpId() {return pId;}

    public void setpId(Integer pId) { this.pId = pId;}

    @Column(name = "Buff_SlotNum", nullable = false)
    public Short getBuffSlotNum() {return buffSlotNum;}

    public void setBuffSlotNum(Short buffSeqNum) { this.buffSlotNum = buffSeqNum;}
}

增益等级

@Entity
@Table(name = "BUFF")
public class Buff {
    private BuffId id;
    private String buffName;
    private Long duration;
    private Set<Item> buffedItems;

    @EmbeddedId
    public BuffId getId() {return id;}

    public void setId(BuffId id) { this.id = id;}

    @Column(name = "Buff_Name", nullable = false, length = 100)
    public String getBuffName() {return buffName;}

    public void setBuffName(String name) { this.buffName = name;}

    @Column(name = "Duration", nullable = false)
    public Long getDuration() {return duration;}

    public void setDuration(Long duration) { this.duration = duration;}

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "BUFFSONITEMS",
        joinColumns = {
            @JoinColumn(name = "P_Id", referencedColumnName = "P_Id"),
            @JoinColumn(name = "Buff_SlotNum", referencedColumnName = "Buff_SlotNum")
        },
        inverseJoinColumns = {
            @JoinColumn(name = "P_Id", referencedColumnName = "P_Id"),
            @JoinColumn(name = "Inv_SlotNum", referencedColumnName = "Inv_SlotNum")
        }
    )
    public Set<Item> getBuffedItems() {return buffedItems;}

    public void setBuffedItems(Set<Item> buffedItems) { this.buffedItems = buffedItems;}
}

每当我尝试启动Spring Boot时,都会出现以下异常 org.hibernate.MappingException:集合中映射的重复列:com.blankd.composite.key.Item.buffs列:P_Id 。 BUFFSONITEMS表使用所有3列作为该表中每一行的主键的一部分。所有三列在各自的表上也都具有伪造的键约束。这意味着P_Id在Buff和Item上都具有forgein键约束。

我不确定我在做什么错,因为我需要P_Id才能唯一标识每个表中的行。

1 个答案:

答案 0 :(得分:1)

您必须选择多对多关系中的一侧作为“拥有”侧。然后,“反”面必须使用mappedBy元素。

如果您选择Item.buffs作为拥有者,则可以这样映射Buff.buffedItems

    @ManyToMany(mappedBy="buffs")
    public Set<Item> getBuffedItems() {return buffedItems;}