Изменения 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 но это похоже на обход реальной проблемы, и я не уверен, что вы не столкнетесь с другими проблемами. Пожалуйста, попробуйте исправить ваше отображение, как я предложил.

Другие вопросы по тегам