Как каскадировать, если объект отсутствует в базе данных, иначе слить?

@Entity
public class Auction{
    @ManyToOne(cascade=CascadeType.MERGE)
    private Member seller;

    @OneToOne(cascade=CascadeType.PERSIST)
    private Question question;
}

@Entity
public class Member{

}

@Entity
public class Question{
    @ManyToOne(cascade=CascadeType.MERGE)
    private Member personAsking;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
}



em.persist(auction);

Как мне сохранить участника, если он не существует, иначе объединить (обновить) его?


person Tim    schedule 08.03.2014    source источник


Ответы (2)


Добавьте в Auction.seller поле CascadeType.PERSIST. Как это:

@Entity
public class Auction{
    @ManyToOne(cascade={CascadeType.MERGE, CascadeType.PERSIST})
    private Member seller;

    .....
}
person Andrei I    schedule 08.03.2014
comment
Я получаю повторяющуюся ошибку первичного ключа в идентификаторе продавца, когда делаю это и пытаюсь сохранить другой класс аукциона, который ссылается на того же продавца. (т.е. продавец уже есть в базе). - person Tim; 08.03.2014
comment
MySQL. Поле id имеет тип int (db = int(11)) и не генерируется, так как оно уже уникально для каждого члена. - person Tim; 08.03.2014
comment
Persist вызывает исключение, если объект существует. Вам нужно использовать слияние. - person Chris; 09.03.2014

Используйте CascadeType.merge и используйте EntityManager.merge(). Слияние проверит, является ли объект новым или нет, и вставит или обновит его соответствующим образом, а каскадная операция будет работать с объектами, на которые ссылаются, таким же образом.

person Chris    schedule 09.03.2014
comment
Это стандартный способ? Я сделал это, но всякий раз, когда я объединяю () аукцион, который уже существует в базе данных (скажем, для обновления некоторых полей), он создает новую строку вопроса в базе данных и теряет старую. Я думаю, это потому, что идентификатор вопроса генерируется автоматически. - person Tim; 09.03.2014
comment
Слияние создает управляемую копию, идентификаторы которой будут установлены после сброса или фиксации. Поэтому, если вы собираетесь повторно использовать аукцион и объединить его позже, вам следует оставить тот, который был возвращен в результате вызова em.merge. В противном случае вызов слияния в старом экземпляре приведет к тому, что JPA найдет вопрос без установленного идентификатора и вставит его, как если бы он был новым. - person Chris; 10.03.2014
comment
Ладно, думаю, я понимаю. Первое и второе слияние могут быть с разницей в месяц - мы, очевидно, не сохраняем ссылку на возвращенный. Другой сайт меняет аукцион в это время. Есть ли способ обойти эту проблему? - person Tim; 10.03.2014
comment
Я не понимаю тогда. Если существует длительное время, и сущность не удерживается, она должна быть каким-то образом прочитана через EntityManager и, таким образом, должны быть установлены правильные ссылки и идентификаторы. Если у вас возникла конкретная проблема с каскадным слиянием, вам следует создать новый вопрос с подробным описанием того, что вы делаете и что происходит. - person Chris; 10.03.2014
comment
Аааааааааааааааааааааааааааааааааааааааааааааааааааааааауа - вызов слияния(аукциона) во второй раз объединит аукцион, но создаст новую строку Вопроса в базе данных, потому что менеджер сущностей не может сказать, что объект Вопроса в более поздней версии Аукциона совпадает с тем, что находится в базе данных (поскольку идентификатор генерируется автоматически). Поэтому просто создает новый. - person Tim; 11.03.2014
comment
Как вы сказали, вопрос должен быть о том, что merge() не работает, как я думал. Итак, большое спасибо за вашу помощь! Я выберу это как правильный ответ, поскольку технически он подходит для вопроса, который я задал, поэтому может быть полезен для будущих пользователей Google. - person Tim; 11.03.2014