JPA слияние вызывает дубликаты - PullRequest
5 голосов
/ 19 декабря 2009

У меня есть классы сущностей ниже. Когда пользователь впервые регистрируется, указываются только имя пользователя и пароль, поэтому список учетных записей («продуманные профили») пуст. Позже, когда они добавляют учетную запись, пользовательский объект обновляется на клиенте, передается на сервер и затем вызывается 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 ]

1 голос
/ 12 ноября 2013

Это известная проблема с использованием слияния, когда коллекции являются списками. К сожалению, сейчас все еще исправлено: HHH-5855

0 голосов
/ 15 апреля 2016

Мое решение этой проблемы заключалось в добавлении к контроллеру дополнительной функции, которая обновляла бы строку с помощью собственного оператора 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();
        }
    }
}
0 голосов
/ 03 августа 2012

Вы пытались:

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

Я думаю, потому что адрес и учетная запись сгенерировали идентификатор, и вы указываете каскад, чтобы вызвать эту проблему.

...