【问题标题】:JPA Merge Is Causing DuplicatesJPA 合并导致重复
【发布时间】:2010-12-28 04:58:54
【问题描述】:

我有下面的实体类。当用户第一次注册时,只提供用户名和密码,因此帐户列表(想想个人资料)是空的。后来,当他们添加一个帐户时,用户对象在客户端更新,传递给服务器,然后调用 entityManager.merge(user)。当用户被合并时,账户被添加到数据库中 6 次,提供的地址被添加 3 次。我不确定为什么。我希望只添加一次帐户,并且只添加一个地址。对可能发生的事情有任何想法吗?

@Entity
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @OneToMany(cascade=CascadeType.ALL)
    @JoinTable(name="user_accounts")
    private List<Account> accounts;

    //...getters and setters ...
}




@Entity
public class Account implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private long id;

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="address")
    private Address address;

    //...getters and setters...

}



@Entity
public class Address implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="street")
    private String street;

    @Column(name="city")
    private String city;

    @Column(name="state")
    private String state;

    @Column(name="zip")
    private String zip;

    //...getters and setters...
}

【问题讨论】:

  • 如果您不更改名称,您可以删除 @Column(name="id") 或 @Column(name="zip") 之类的内容。
  • 实时服务器默认为所有大写的表和列名,而我的测试服务器默认为小写,所以看起来比更改设置更容易。
  • 您找到解决方案了吗?
  • 从来没有,但我猜这是级联更新导致创建多个实体的结果
  • 您是否尝试过覆盖这些类的equals 方法?

标签: java jpa merge duplicates


【解决方案1】:

您是否尝试过:

persist(address)
account.setAddress(address)
persist(account)
user.setAccount(account)
merge(user)

我认为是因为 addressaccount 生成了 id 并且您指定 cascade 导致了这个问题。

【讨论】:

    【解决方案2】:

    这是在集合是列表的情况下使用合并的一个已知问题。不幸的是,现在还没有真正修复:HHH-5855

    【讨论】:

    • 在 5.0.8 版本中修复
    【解决方案3】:

    我对此问题的解决方案是向控制器添加一个附加函数,该函数将使用本机 SQL 语句更新行。由于我的代码更新了部分或密钥(长篇大论,但令人惊讶地工作得非常好),我必须确保我不是根据 pojo 中的新值查找记录。这是代码:

    public void editSQLUpdate(Reportinfo reportinfo) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            String qry = "UPDATE `boeaudit`.`reportinfo` "
                    + "SET "
                    + "`author` = '" + reportinfo.getAuthor() + "',"
                    + "`db_account` = '" + reportinfo.getDbAccount() + "',"
                    + "`db_schema_name` = '" + reportinfo.getDbSchemaName() + "',"
                    + "`descriptions` = '" + reportinfo.getDescriptions() + "',"
                    + "`DLL` = '" + reportinfo.getDll() + "',"
                    + "`parent_folder` = " + reportinfo.getParentFolder() + ","
                    + "`path` = '" + reportinfo.getPath() + "',"
                    + "`report_title` = '" + reportinfo.getReportTitle() + "',"
                    + "`report_id` = " + reportinfo.getReportinfoPK().getReportId() + ","
                    + "`env` = " + reportinfo.getReportinfoPK().getEnv() + ","
                    + "`db_server` = '" + reportinfo.getReportinfoPK().getDbServer() + "',"
                    + "`seq` = " + reportinfo.getReportinfoPK().getSeq() 
                    + " WHERE `report_id` = " + reportinfo.getReportinfoPK().getReportId()
                    + " AND `env` = " + reportinfo.getReportinfoPK().getEnv()
                    + " AND `db_server` = '-'" //this is the initial value of the record and the update value differs, so if we pass the new value the record will not be found. ;)
                    + " AND `seq` = "+ reportinfo.getReportinfoPK().getSeq();
            Query nq = em.createNativeQuery(qry);
            int outcome = nq.executeUpdate(); //not doing anything with outcome, but should be used to determine the result of the operation...
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                ReportinfoPK id = reportinfo.getReportinfoPK();
                if (findReportinfo(id) == null) {
                    throw new NonexistentEntityException("The reportinfo with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-05
      • 2015-01-24
      • 2015-01-06
      • 2015-04-11
      • 2012-01-18
      • 2019-02-09
      • 2019-10-09
      • 2018-08-30
      相关资源
      最近更新 更多