JPA合并导致重复

时间:2009-12-18 22:11:02

标签: java jpa merge duplicates

我有下面的实体类。当用户首次注册时,仅提供用户名和密码,因此帐户列表(思考配置文件)为空。稍后,当他们添加帐户时,会在客户端更新用户对象,传递给服务器,然后调用entityManager.merge(user)。合并用户时,会将帐户添加6次到数据库,并将提供的地址添加三次。我不知道为什么。我想要添加一次帐户,只添加一个地址。关于可能发生的事情的任何想法?

@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...
}

3 个答案:

答案 0 :(得分:1)

这是使用合并的已知问题,其中集合是列表。不幸的是现在真正修复了:HHH-5855

答案 1 :(得分:0)

您是否尝试过:

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

我认为因为地址帐户已经生成了ID,并且您指定了级联导致此问题。

答案 2 :(得分:0)

我对此问题的解决方案是向控制器添加一个额外的函数,该函数将使用本机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();
        }
    }
}