【问题标题】:Composite ID in Hibernate how to map Key classHibernate中的复合ID如何映射Key类
【发布时间】:2017-10-14 02:55:45
【问题描述】:

如何实现复合键,让我们做一个非常简单的例子,用户参加活动,三个数据库表:User、Event、Users_Attending_Events 最后一个表有三个列:userID、eventID;它们与其他两个表的各自 ID 和成功连接,这决定了用户是否向事件炫耀。

我希望Attending 是一个单独的类,不要直接加入User 和Event,因为Attending 包含“成功”信息,必须单独管理。

我的实现

用户对象:

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

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer userID;
    @JsonIgnore
    @OneToMany(mappedBy = "attend", targetEntity = Attending.class, fetch = FetchType.LAZY)
    private Set<Attending> attendEvents = new HashSet<Attending>();
...
// setters, getters, constructors, equal and hash ...
}

事件:

@Entity
@Table(name = "events")
public class Event implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer eventID;
    @JsonIgnore
    @OneToMany(mappedBy = "attend", targetEntity = Attending.class, fetch = FetchType.LAZY)
    private Set<Attending> participants = new HashSet<Attending>();
...
// setters, getters, constructors, equal and hash ...
}

上课:

@Entity
@Table(name = "users_attending_events")
public class Attending implements Serializable {

        @EmbeddedId
        protected AttendingID attend;

        private Integer success;
    ...
    // setters, getters, constructors, equal and hash ...
    }

AttendingID 类,用于复合键:

  @Embeddable
  public class AttendingID implements Serializable {

        @ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
        @JoinColumn(name = "users_userID", referencedColumnName = "userID")
        private Integer user;

        @ManyToOne(targetEntity = Event.class, fetch = FetchType.LAZY)
        @JoinColumn(name = "events_eventID", referencedColumnName = "eventID")
        private Integer event;
    ...
    // setters, getters, constructors, equal and hash ...
    }

运行时出现异常:

org.hibernate.MappingException: Foreign key (FKlerh9fv4q1rjiusg0ful3m15j:users_attending_events [events_eventID,users_userID])) must have same number of columns as the referenced primary key (users [userID])

我错过了什么?

【问题讨论】:

    标签: java spring hibernate jpa hibernate-mapping


    【解决方案1】:

    问题:

    异常很简单地说映射的外键不是预期的类型,而您的问题是您试图将@ManyToOne 关系映射到Integer 类型的属性中,这是错误的部分。

    解决方案:

    @ManyToOne 注释应该引用映射 Entity 在您的情况下为 UserEvent,而不是原始类型或实体的主键。

    但要定义 Embeddable 主键,您有两个选择:

    1. 仅使用映射实体主键作为 Embeddable 类中的属性。

    您的代码将是:

    @Embeddable
    public class AttendingID implements Serializable {
    
        @Column(name = "users_userID")
        private Integer userID;
    
        @Column(name = "events_eventID")
        private Integer eventID;
    
        ...
        // setters, getters, constructors, equal and hash ...
    }
    
    1. 或者在您的可嵌入主键中使用两个映射实体作为属性,并使用@ManyToOne 注释来引用它们。

    因此,在您的代码中,您只需要更改 user

    的类型
    @Embeddable
    public class AttendingID implements Serializable {
    
        @ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
        @JoinColumn(name = "users_userID", referencedColumnName = "userID")
        private User user;
    
        @ManyToOne(targetEntity = Event.class, fetch = FetchType.LAZY)
        @JoinColumn(name = "events_eventID", referencedColumnName = "eventID")
        private Event event;
    
        ...
        // setters, getters, constructors, equal and hash ...
    }
    

    文档:

    如需进一步阅读和更多选项,您可以查看5.1.2.1. Composite identifier Section in Hibernate Mapping Documentation,它清楚地显示并解释了映射复合主键的所有可能情况。


    编辑:

    重新阅读您的问题后,更好地专注于问题并从 vue 的设计角度思考它,我认为您的情况会更好地说明 ManyToMany 关系UserEvent 实体之间的连接表 Attending 有一个额外的列 success,它将更好地处理您的情况并解决问题。

    我建议你看看这个Hibernate Many-to-Many Association with Extra Columns in Join Table Example tutorial 它显示了一个类似的ManyToMany 解决方案。

    【讨论】:

    • 谢谢,我更正了我的代码,首先使用你的选项 1,我得到了完全相同的异常;然后我尝试使用选项 2,但仍然得到相同的异常,我注意到 User 或 Event 中的引用:@OneToMany(mappedBy = "attend", targetEntity = Attending.class, fetch = FetchType.LAZY) private Set attendEvents = new HashSet();这个地方的键 mappedBy =”attend” 错了吗?
    • @mattobob 在mappedBy 中,我们使用映射另一侧的属性名称,因此应分别为mappedBy="user"mappedBy="event"
    • 现在更正我得到异常:AnnotationException:mappedBy 引用未知目标实体属性:model.User.attendEvents 中的model.Attending.user; Attending.user 未定义,但 AttendingID.user
    • 是的,因为目标实体映射在ÈmbeddedIs`而不是实体中,你应该更好地使用option1并将@ManyToOne(fetch = FetchType.LAZY) private User user;@ManyToOne(fetch = FetchType.LAZY) private Event event;映射到Attending实体中,你可以检查this tutorial它也显示了一个解决方案。
    • 我明白吗,没有嵌入类?没有人这是我一开始做的,它不起作用,当尝试存储一个主治时它会引发类型不同的异常
    猜你喜欢
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 1970-01-01
    • 2021-12-12
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多