Я хочу сохранить/сохранить объект (родительский) с уникальными дочерними объектами, включенными только родительским объектом. Все работает хорошо, пока не появится дубликат ребенка, здесь я получаю следующее исключение:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry
Сначала вы должны знать, что я использую выражение session.bySimpleNaturalId(Child.class).load(child.getMd5Hash())
чтобы проверить, существует ли уже этот дочерний объект, поскольку все дочерние объекты имеют уникальные значения хэша (созданные после инициализации), которые явно не назначены в качестве первичного ключа (их первичный ключ является автоматическим приращением; strategy = GenerationType.TABLE
).
Я использую session.merge(child)
или любое другое выражение в моем DAO, я получаю то же исключение.
Мой родитель-объект:
@Entity
@Table(name = "parent")
public class Parent implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id = null;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "kind_child_id", referencedColumnName = "md5hash")
private Child firstChild;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "rude_child_id", referencedColumnName = "md5hash")
private Child secondChild;
//private String attributes;
//Getters & Setters
Мой ребенок-объект:
@Entity
@Table(name = "child")
public class Child implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id = null;
@NaturalId
@Column(name="md5hash", unique=true)
private char[] md5hash = new char[32];
//private String attributes;
//Getters & Setters
И вот мой метод сохранения/сохранения родителя (включая проверки):
public void writeParent(Parent parent) {
try {
if (parent != null) {
if (globalSession == null) {
globalSession = getSessionFactory().openSession();
}
globalSession.beginTransaction();
if (parent.getFirstChild() != null) {
Child tempFirstChild = (Child) globalSession.bySimpleNaturalId(Child.class).load(parent.getFirstChild().getMd5Hash());
if (tempFirstChild != null) {
parent.setFirstChild(tempFirstChild);
//globalSession.merge(tempFirstChild);
//throws MySQLICV-Exception
//globalSession.update(tempFirstChild);
//throws MySQLICV-Exception
}
}
if (parent.getSecondChild() != null) {
Child tempSecondChild = (Child) globalSession.bySimpleNaturalId(Child.class).load(parent.getSecondChild().getMd5Hash());
if (tempSecondChild != null) {
parent.setSecondChild(tempSecondChild);
//globalSession.merge(tempSecondChild);
//throws MySQLICV-Exception
//globalSession.update(tempSecondChild);
//throws MySQLICV-Exception
}
}
globalSession.saveOrUpdate(parent);
//globalSession.persist(parent);
globalSession.getTransaction().commit();
}
} catch (Exception ex) {
log.error("FAILURE: ", ex);
}
finally{
globalSession.close();
}
}
Возможно, я не понял весь документальный фильм, почему я придумал это: мне даже нужно сказать Hibernate объединить найденные объекты? Как я могу сказать Hibernate, что этих детей нельзя рассматривать как новые объекты, которые необходимо сохранить? Или мне даже нужно переключиться на двунаправленные отношения (в данном случае мне не разрешено использовать двунаправленные отношения)
Любые подсказки приветствуются и очень ценятся, заблаговременно. С уважением, Yeti
Я сам нашел ответ, иначе. Сначала, чтобы исправить это, я использовал отдельную функцию, чтобы проверить, существует ли дочерний элемент, кроме того, я использовал отдельные сеансы для их проверки (возможно, он не работает, если L2C отключен).
synchronized public Child checkChild(Child child) {
try {
if (child != null) {
tempSession = getSessionFactory().openSession();
Child tempChild = (Child) tempSession.bySimpleNaturalId(Child.class).load(Child.getMd5Hash());
if (tempChild != null) {
return tempChild;
} else {
return child;
}
} else {
return null;
}
} catch (Exception ex) {
return null;
}
finally{
tempSession.close();
}
}
Во-вторых, и есть подсказка, я попытался сохранить родительский объект как параметрическое значение, что неверно, поэтому просто инициируйте новый родительский объект внутри метода и сделайте это.
public void writeParent(Parent parent) {
tempParent = new Parent();
tempParent.setFirstChild(checkChild(tempParent.getFirstChild()));
tempParent.setSecondChild(checkChild(tempParent.getSecondChild()));
globalSession = getSessionFactory().openSession();
globalSession.beginTransaction();
globalSession.saveOrUpdate(tempParent);
globalSession.getTransaction().commit();
globalSession.close();
}