【问题标题】:ManyToMany on itself with AssociationTable with EmbeddedId - Spring-Data-JpaManyToMany 本身带有带有 EmbeddedId 的 AssociationTable - Spring-Data-Jpa
【发布时间】:2019-03-16 08:53:23
【问题描述】:

在多对多关联期间我遇到了休眠问题:/ 我希望有一个用户和他的联系人。 关联表用于具有关联的创建日期及其状态(例如活动、非活动等...)

  • 休眠版本:5.2.17
  • 弹簧靴:2.0.5

我的班级用户:

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

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "assoc_user_user", joinColumns = {@JoinColumn(name = 
"id.myself.id")}, inverseJoinColumns = {@JoinColumn(name = 
"id.contact.id")})
private List<AssocUserUser> contacts;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "assoc_user_user", joinColumns = {@JoinColumn(name = 
"id.contact.id")}, inverseJoinColumns = {@JoinColumn(name = 
"id.myself.id")})
private List<AssocUserUser> contactOf;

}

我的关联类 AssocUserUser :

@Entity(name = "assoc_user_user")
public class AssocUserUser implements Serializable {

private static final long serialVersionUID = 1L;

@EmbeddedId
private AssocUserUserId id;

@Column(name = "creation_date", nullable = false)
private LocalDateTime creationDate;

@Column(name = "status")
@Enumerated(EnumType.STRING)
private ContactStatusEnum status;

}

我的 EmbeddedId 类 AssocUserUserId :

@Embeddable
public class AssocUserUserId implements Serializable {

private static final long serialVersionUID = 1L;

@ManyToOne
@JoinColumn(name = "user_id_myself", nullable = false)
private User myself;

@ManyToOne
@JoinColumn(name = "user_id_contact", nullable = false)
private User contact;

}

我的错误:

引起:org.hibernate.AnnotationException:外键引用 com.....AssocUserUser 来自 com.....User 的数量错误 柱子。应该是 2

【问题讨论】:

    标签: java spring jpa spring-data-jpa many-to-many


    【解决方案1】:

    嗯,这个问题已经在Spring-Data-JPA ManyToMany relationship with extra column 提出并回答了,但我想这与自我参考有点不同。我不是所有JoinTableJoinColumn 注释的忠实粉丝,但这只是因为它们通常是多余的,而且恕我直言,用于更改默认值。我的答案不包括这些注释,因此请根据需要添加它们。请注意,对于 Spring-Data-Jpa,您需要每个实体的存储库,因此您需要关联实体的存储库。这与 JPA 中的单个实体管理器不同。这会稍微影响您处理关联实体的方式。在这里,我们通过创建和持久化新的AssocUserUser 实体来持久化新关系。

    我上课的方式是:

    @Entity
    public class User {
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @OneToMany(mappedBy="myself")
        private Set<AssocUserUser> contacts;
    
    @Entity
    public class AssocUserUser {
        @EmbeddedId
        private AssocUserUserId id = new AssocUserUserId();
        @ManyToOne @MapsId("myselfId")
        private User myself;
        @ManyToOne @MapsId("contactId")
        private User contact;
    
    @SuppressWarnings("serial")
    @Embeddable
    public class AssocUserUserId implements Serializable {
        private Long myselfId;
        private Long contactId;
    

    Repositories 两个实体

    public interface UserRepository extends JpaRepository<User, Long> {
        @Query("select u from User u left outer join fetch u.contacts where u.id = :userId")
        User getContactsForUser(@Param("userId") Long userId);
    
    public interface AssocUserUserRepository extends JpaRepository<AssocUserUser, AssocUserUserId> {
    

    如何创建关联

    private void update() {
        User user1 = new User();
        User contact1 = new User();
        userRepo.save(user1);
        userRepo.save(contact1);
        AssocUserUser assoc = new AssocUserUser();
        assoc.setMyself(user1);
        assoc.setContact(contact1);
        assocUserUserRepo.save(assoc);
    }   
    

    如何以Unidirectional 的方式阅读关联

    private void read() {
        User me = new User();
        me.setId(1L);
        AssocUserUser assoc = new AssocUserUser();
        assoc.setMyself(me);
        List<AssocUserUser> contacts = assocUserUserRepo.findAll(Example.of(assoc));
        System.out.println(contacts.size());
    }
    

    并以Bidirectional 的方式阅读关联:

    private void readBi() {
        User me = userRepo.getContactsForUser(1L);
        System.out.println(me.getContacts().size());
    }
    

    和往常一样,检查日志:

    create table assoc_user_user (contact_id bigint not null, myself_id bigint not null, primary key (contact_id, myself_id))
    create table user (id bigint generated by default as identity, primary key (id))
    alter table assoc_user_user add constraint FKaccetv956cu63fwiejjfrm0mi foreign key (contact_id) references user
    alter table assoc_user_user add constraint FK1absxfuktrjnom8vwtjfqx5l0 foreign key (myself_id) references user
    
    insert into user (id) values (null)
    insert into user (id) values (null)
    select assocuseru0_.contact_id as contact_1_0_0_, assocuseru0_.myself_id as myself_i2_0_0_ from assoc_user_user assocuseru0_ where assocuseru0_.contact_id=? and assocuseru0_.myself_id=?
    select user0_.id as id1_1_0_ from user user0_ where user0_.id=?
    select user0_.id as id1_1_0_ from user user0_ where user0_.id=?
    insert into assoc_user_user (contact_id, myself_id) values (?, ?)
    
    select assocuseru0_.contact_id as contact_1_0_, assocuseru0_.myself_id as myself_i2_0_ from assoc_user_user assocuseru0_ inner join user user1_ on assocuseru0_.myself_id=user1_.id where user1_.id=1
    select user0_.id as id1_1_0_ from user user0_ where user0_.id=?
    select user0_.id as id1_1_0_ from user user0_ where user0_.id=?
    
    select user0_.id as id1_1_0_, contacts1_.contact_id as contact_1_0_1_, contacts1_.myself_id as myself_i2_0_1_, contacts1_.myself_id as myself_i2_0_0__, contacts1_.contact_id as contact_1_0_0__ from user user0_ left outer join assoc_user_user contacts1_ on user0_.id=contacts1_.myself_id where user0_.id=?
    select user0_.id as id1_1_0_ from user user0_ where user0_.id=?
    

    【讨论】:

    • 感谢您的大力帮助! :) 是的,我写了一个新帖子,因为它本身“。我不知道@MapsId!非常感谢,答案非常完整和有用。
    猜你喜欢
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 2020-05-20
    • 2017-04-21
    • 2016-03-26
    • 2022-01-02
    • 2015-07-30
    相关资源
    最近更新 更多