【问题标题】:many-to-many JPA mapping inserting but not fething the child collections多对多 JPA 映射插入但不支持子集合
【发布时间】:2009-11-20 20:49:17
【问题描述】:

我再次遇到了 hibernate 的障碍。我已经多次发布了关于我一直在构建的用户和联系人管理的不同方面的文章。

可悲的是,在真正开始使用它之前,我真的没有时间玩它并更好地理解它。抱歉,英语不是我的母语,我宁愿说法语。我又一次开始以自学的方式在 Java 中编码。我通过阅读书籍来完成所有这些工作,而且还没有上过学。由于时间限制,很难从头到尾读完一本书。
我不确定我是否应该将处理问题的每个代码都放在这里,并且从我从其他论坛中学到的内容是发布必要且简洁的内容。

所以在我的用户模型中,我有 UserAccount 类、包含名称、首选项等详细信息的配置文件、AccountSession 和电话。 我的联系人管理模型有联系人和组。

UserAccount 与 Profile 一对一关联,与 AccountSession、contact 和 group 一对多关联,都是双向的。与 phone 的一对多关联是单向的,因为 contact 也与 Phone 具有单向关联。

联系人有一个双向的多对多与组和一对多与电话,我之前说过。 组也有一个多对多的方向性联系。

这里是映射

// UserAccount 
 ......
 @OneToOne(targetEntity=UserProfileImpl.class,cascade={CascadeType.ALL})
 @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@JoinColumn(name="USER_PROFILE_ID")
private UserProfile profile;

@OneToMany(targetEntity=ContactImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Contact> contacts = new HashSet<Contact>();

@OneToMany(targetEntity=GroupImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Group> groups = new HashSet<Group>();
.......

//Group
     @ManyToOne(targetEntity=UserAccountImpl.class)
@JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;

@ManyToMany(targetEntity=ContactImpl.class,cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name="GROUP_CONTACT_MAP", joinColumns={@JoinColumn(name="GROUP_ID")},
inverseJoinColumns={@JoinColumn(name="CONTACT_ID")})
private Set<Contact> contacts = new HashSet<Contact>();

//Contact
 ....
 @ManyToOne(targetEntity=UserAccountImpl.class)
@JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;

@ManyToMany(targetEntity=GroupImpl.class, mappedBy="contacts")
private Set<Group> groups=new HashSet<Group>();
....

// helper methods from group
public void addContact(Contact contact) {
    try{
        this.getContacts().add(contact);
        contact.getGroups().add(this);
    }catch(Exception e) {

    }

}

//helper method from group
public void removeContact(Contact contact) {
    contact.getGroups().remove(contact);
    this.getContacts().remove(contact);

}

//helper method from contact   
public void addGroup(Group group) {
    try{
        this.getGroups().add(group);
        group.getContacts().add(this);
    } catch(Exception e) {
        e.printStackTrace();
    }
}

//Helper method from group
public void removeGroup(Group group){
     try{

        group.getContacts().remove(this);
        this.getGroups().remove(group);
    } catch(Exception e) {
        e.printStackTrace();
    }
}

//来自Contact的UserAccount setter。所有多对一的孩子都有相同的 /** * @param userAccount 要设置的用户帐户 */ 公共无效 setUserAccount(用户帐户用户帐户){ this.userAccount = 用户帐户; }

我想通过电子邮件字段提取 UserAccount,该字段是 UserAccount 表中的唯一字段。
在 UserAccountDAO 中,我调用以获取 UserAccount 的方法是 getUserAccountByEmail,如下所示。所以我希望这个方法能够加载 UserAccount 的所有子集合,即它的联系人集合、组集合。我希望它以这样一种方式加载 UserAccount使用 Contacts 集合,每个联系人对象都有其所属组集合(如果有)的引用,反之亦然。

 public UserAccount getUserAccountByEmail(String email) {
 //       try {
       logger.info("inside getUserAccountByEmail");
       logger.debug(email);
        Session session = (Session) this.getDBSession().getSession();
        UserAccount user = (UserAccount) session.createCriteria(this.getPersistentClass())
                .setFetchMode("contacts", FetchMode.SELECT) //recently added
                .setFetchMode("groups", FetchMode.SELECT) // recently added
                .add(Restrictions.eq("email", email))
                .uniqueResult();
        logger.debug(user);
        return user;
 //       } catch(NonUniqueResultException ne) {
//           logger.debug("Exception Occured: getUserAccountByEmail returns more than one result  ", ne);
//           return null;
//       } catch(HibernateException he){
//           logger.debug("Exception Occured: Persistence or JDBC exception in method  getUserAccountByEmail ",he);
//           return null;
//       }catch(Exception e) {
//           logger.debug("Exception Occured: Exception in method getUserAccountByEmail", e);
//           return null;
//       }

由于在任何联系人和组之前必须有一个 UserAccount,因此在我的单元测试中,当测试保存必须存在现有组的联系人对象时,我会按顺序执行此操作
a 创建 userAccount 对象 ua。
b 创建组对象 g1;
c 创建联系人对象 c1;
d ua.addGroup(g1);
e c1.setUserAccount(ua);
f c1.addGroup(g1);
g uaDao.save(ua); // 由于级联而保存组
h cDao.save(c1);

大多数时候,我使用 hibernate 中的 session.get() 来通过 hibernate 生成的 it id 提取 c1 并执行所有实际有效的断言。

但是在集成测试中,当我使用和不使用 setFetchMode 调用 getUserAccountByEmail 时,它会返回正确的对象,但是所有子集合都是空的。我已经尝试了 JOIN 和 SELECT。查询字符串发生了变化,但结果集仍然相同。所以这就产生了一些问题:

1. 我应该怎么做才能解决这个问题?
2. 辅助方法工作正常,但它在父端(我在测试中这样做) ). 我一直想知道的是做 c1.setUserAccount(ua);足以在 UserAccount 和联系人之间建立牢固的关系。大多数情况下,不会有我将 userAccount 与联系人一起保存的情况,但是之前不会调用在双方设置关联且位于 UserAccount 中的辅助方法我保存了特定用户帐户的联系人。所以我对此有点困惑,并怀疑关联的设置是某些事情无法正常工作的一部分。然后调用 session.get(UserAccount.class, ua.getID( )) 我认为这是我想要的,我希望 getUserAccountByEmail 也这样做。
3. ChssPly76 认为必须重写映射。所以我愿意让你指导我通过这个。我真的需要知道正确的方法来做到这一点,因为我们不能从一本好书中学习所有内容。所以我认为我应该改变映射只是告诉我如何做。很可能我做错了事情甚至没有意识到这一点,所以不要忘记我还在学习 java 本身。谢谢s 的建议和评论,感谢您阅读本文

【问题讨论】:

    标签: java hibernate jpa jakarta-ee


    【解决方案1】:

    我同意您的观点,您的父对象与其子集合之间的关联似乎没有得到正确持久化。我总是喜欢从查看数据库中的内容开始,以了解发生了什么。运行测试后,您在实际数据库中看到了什么?

    似乎有两种情况之一正在发生(以 UserAccount 为例):

    1. 子集合中的项目根本没有保存到数据库中,在这种情况下,您将能够在数据库中看到没有与您的 UserAccount 关联的记录。这可能是由于在将子对象添加到 UserAccount 的集合之前保存了 UserAccount 对象。

    2. 子集合中的项目正在保存到数据库中,但没有与父对象所需的关联,在这种情况下,您将看到子项目的行,但连接列(即“userAccount”)将为空)。这可能是由于未在子对象上设置 userAccount() 属性造成的。

    这是我遇到的两种情况,我看到了您描述的问题。首先查看数据库中的内容,看看是否能引导您走得更远。

    【讨论】:

      猜你喜欢
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-15
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多