Изменения JPA IndirectSet, не отраженные в веб-интерфейсе Spring
РЕДАКТИРОВАТЬ: Решено, но я не знаю, что изменилось сейчас. Если кто-то может объяснить, что произошло по-другому, я был бы признателен.
Теперь он работает, объединяя только Родителя, а не Дитя, вот так:
Parent parent = child.getParent();
parent.getChildren().add(child);
getJpaTemplate().merge(parent);
Теперь, похоже, это работает, но я не совсем понимаю, почему это будет работать, в то время как моя предыдущая попытка не сработала.
Оригинальная попытка / вопрос:
У меня проблема с Spring JPA и IndirectSets. У меня есть две сущности, Родитель и Дитя, определенные ниже. У меня есть форма Spring, в которой я пытаюсь создать нового дочернего элемента и связать его с существующим родительским элементом, а затем отразить все в базе данных и в веб-интерфейсе. Происходит то, что он помещается в базу данных, но пользовательский интерфейс, похоже, не согласен.
Две сущности, которые связаны друг с другом в отношении OneToMany, примерно так:
@Entity
@Table(name = "parent", catalog = "myschema", uniqueConstraints = @UniqueConstraint(columnNames = "ChildLinkID"))
public class Parent {
private Integer id;
private String childLinkID;
private Set<Child> children = new HashSet<Child>(0);
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "ChildLinkID", unique = true, nullable = false, length = 6)
public String getChildLinkID() {
return this.childLinkID;
}
public void setChildLinkID(String childLinkID) {
this.childLinkID = childLinkID;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
public Set<Child> getChildren() {
return this.children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}
}
@Entity
@Table(name = "child", catalog = "myschema")
public class Child extends
private Integer id;
private Parent parent;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ChildLinkID", referencedColumnName = "ChildLinkID", nullable = false)
public Parent getParent() {
return this.parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
И конечно же, разбираются простые свойства на каждом из них. Теперь проблема в том, что когда я редактирую эти простые свойства из моего интерфейса Spring, все работает прекрасно. Я могу сохранить новые объекты этих типов, и они появятся при использовании JPATemplate для поиска, скажем, всех Parents (getJpaTemplate(). Find("select p from Parent p")) или отдельных объектов по ID или другая собственность.
Проблема, с которой я сталкиваюсь, заключается в том, что теперь я пытаюсь создать нового потомка, связанного с существующим родителем через ссылку со страницы родителя. Вот важные биты контроллера (обратите внимание, что я поместил JPA foo в контроллер здесь, чтобы сделать его более понятным; фактический JpaDaoSupport фактически находится в другом классе, соответственно, многоуровневом):
protected Object formBackingObject(HttpServletRequest request) throws Exception {
String parentArg = request.getParameter("parent");
int parentId = Integer.parseInt(parentArg);
Parent parent = getJpaTemplate().find(Parent.class, parentId);
Child child = new Child();
child.setParent(parent);
NewChildCommand command = new NewChildCommand();
command.setChild(child);
return command;
}
protected ModelAndView onSubmit(Object cmd) throws Exception {
NewChildCommand command = (NewChildCommand)cmd;
Child child = command.getChild();
child.getParent().getChildren().add(child);
getJpaTemplate().merge(child);
return new ModelAndView(new RedirectView(getSuccessView()));
}
Как я уже сказал, я могу пройти через форму и заполнить новые значения для ребенка - данные родителя даже не отображаются. Когда он возвращается к контроллеру, он проходит и сохраняет его в базовой базе данных, но интерфейс никогда не отражает его. Как только я перезапускаю приложение, оно все там и заполняется соответствующим образом.
Что я могу сделать, чтобы прояснить это? Я пытался вызвать дополнительные слияния, пытался обновить (что дало исключение транзакции), все, кроме написания собственного кода доступа к базе данных. Я удостоверился, что у каждого класса есть соответствующие equals() и hashCode(), есть полная отладка JPA, чтобы видеть, что он делает соответствующие вызовы SQL (он, кажется, не делает никаких новых вызовов к таблице Child), и пошаговый через отладчик (все это в IndirectSets, как и ожидалось, и между сохранением и отображением Parent объект получает новый адрес памяти). Каков мой следующий шаг?
1 ответ
Я не уверен, что это как-то связано с вашей проблемой, но почему у вас есть childLinkID
собственность в вашем Parent
учебный класс? Это кажется странным, особенно если вы используете соответствующий столбец для объединения. Интересно, как все может работать с этим отображением, и я бы это исправил. Можете ли вы попробовать без (также удалить referencedColumnName
, тебе это не нужно)?
И, кстати, почему бы вам не установить обе стороны связи между Parent
а также Child
в том же методе? Это делает код трудным для чтения и поддержки IMO.
Вы редактировали вопрос, пока я отвечал, и изменили каскадное Parent
в Child
но это похоже на обход реальной проблемы, и я не уверен, что вы не столкнетесь с другими проблемами. Пожалуйста, попробуйте исправить ваше отображение, как я предложил.