消除一对多关系引用

时间:2017-01-21 00:21:37

标签: java mysql postgresql hibernate one-to-many

我目前正在使用一个程序,每次运行程序时都会收到三个数字值(companyName,groupName,hostName)。每次收到这三个值时,我都会将它们分组为一个对象(Datas)并将它们存储在List(List)中。

我的目标是将所有值存储到具有三个表(公司,组,主机)的数据库中。

这三个表是相连的:公司是一对多的集团,集团是一对多的主机。

所以我创建了三个类(Company.java,Group.java,Host.java),它们将采用适当的值并使用构造函数创建类的新实例。

然后我会使用hibernate session将类的每个实例存储到数据库中。

我的代码是这样的:

for (Datas data:Datas){
     Company company = new Company(data.getCompanyName);
     Group group = new Group(company, data.getGroupName);
     Host host = new Host(group, data.getHostName);

     session.save(company);
     session.save(group);
     session.save(host);     
}

虽然上面的代码允许我使用正确的一对多关系将我的所有数据保存到我的表中,但它不允许我阻止重复条目。

例如,现在我的表在保存5个数据后以这种方式存储:

Company
id (auto-increment)  Name
1                    Google
2                    Google
3                    Google
4                    Yahoo
5                    Yahoo

Group
id (auto-increment)  Company_id  Name
1                    1           HR
2                    2           HR
3                    3           OP
4                    4           HR
5                    5           PR

Host
id (auto-increment)  Group_id  Name
1                    1         Jane
2                    2         Harry
3                    3         Molly
4                    4         Garry
5                    5         Neo   

虽然上面的表在技术上是正确的,但我真的想要消除重复。现在在公司表中,所有“Google”和“Yahoo”条目完全相同。在Group表格中,第一个和第二个条目是相同的,因为它们都具有名称“HR”,并且它们都引用了公司“Google”。

这种方式而不是创建3个公司条目“Google”,我们只会创建1.而Group表上的所有条目只会引用该条目。主机表的逻辑相同。

正确的表应如下所示:

Company
id (auto-increment)  Name
1                    Google
2                    Yahoo

Group
id (auto-increment)  Company_id  Name
1                    1           HR
2                    1           OP
3                    2           HR
4                    2           PR

Host
id (auto-increment)  Group_id  Name
1                    1         Jane
2                    1         Harry
3                    3         Molly
4                    4         Garry
5                    5         Neo   

如何在我的代码中进行此类调整?在实例化三个类之前,我应该对数据做些什么吗?或者我应该在使用类构造函数实例化时做些什么?或者是否有可用于防止此类重复的Hibernate注释?

非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

您的for循环应基本上根据业务自然键值查询数据库,并根据该事实确定记录是否存在和分支。

for ( Datas data : datas ) {
  Company company = companyRepository.findByName( data.getCompanyName() );
  if ( company == null ) {
    // new company implies everything else is also new
    company = new Company( data.getCompanyName() );
    group = new Group( company, data.getGroupName() );
    host = new Host( group, data.getHostName() );
    session.save( company );
    session.save( group );
    session.save( host );
  }
  else {
    // since company exists, we need to check whether group/host exist
    Group group = groupRepository.findByName( data.getGroupName() );
    if ( group == null ) {
      // since group doesn't exist, neither will host
      group = new Group( company, data.getGroupName() );
      host = new Host( group, data.getHostName() );
      session.save( group );
      session.save( host );
      // depending on relationships, you may need to link group to company
      // followed by updating company.
    }
    else {
      // group exists, check if host does
      Host host = hostRepository.findByName( data.getHostName() );
      if ( host == null ) {
        // host doesn't, create it.
        host = new Host( group, data.getHostName() );
        session.save( host );
        // depending on relationships, you may need to link host to group
        // followed by updating group.
      }
    }
  }
}

公开#findByName(String)方法的各种存储库类仅用于说明使用查找实体的指定名称的谓词执行的查询。

显然,如果你的Datas结构带有更多细节,而不仅仅是一个名称值,它还需要与现有记录合并,你需要在循环中添加逻辑以对持久化应用任何修改#findByName(String方法提取的对象。

// Simplified example for the Host
Host host = hostRepository.findByName( data.getHostName() );
if ( host == null ) {
  host = new Host( group, data.getHostName() );
  host.setSomeOtherAttribute( data.getHostSomeOtherAttribute() );
  session.save( host );
}
else {
  host.setsomeOtherAttribute( data.getHostSomeOtherAttribute() );
  session.update( host );
}