спящий круговой внешний ключ - PullRequest
3 голосов
/ 18 августа 2010

Я должен проверить код, который сам не написал.Это интеграционный тест: приложение постоянно работает на сервере, и мои тесты выполняются на нем.

Тесты - это тесты Selenium, они запускают браузер, выполняют в нем некоторый JavaScript для имитации действий пользователя и проверяют,база данных правильно обновлена.Я должен восстанавливать базу данных до ее исходного состояния после каждого.

Для этого я использую аннотации Spring и Hibernate через DAO, которые я сам не написал.

Проблема в том, что существуют циклическиевнешние ключи.Объект класса A имеет связь OneToMany с объектами типа B, а также существует связь ManyToOne с тем же классом.Я пытаюсь удалить объект типа A и все связанные с ним объекты B в одной и той же транзакции, но он не работает , поскольку Hibernate пытается установить «defaultB» в ноль перед удалением объекта типа A .Совершенно не нужно его аннулировать, хотя имеет смысл делать это после удаления указанного объекта типа B.

Я (наивно) подумал, что, поскольку две операции были выполнены в одной транзакции, удалениеобъект "a" типа A, ссылающийся (и на который ссылается) объект "b" класса B и удаляющий b одновременно, не будет проблемой.Однако я был совершенно неправ.Есть ли способ сделать это без изменения модели БД (которую я не написал)?

Обновление 1 : я не понимаю, почему, когдаЯ выполняю mySession.delete (B), Hibernate пытается обнулить ключ, который он знает как необнуляемый ... какие-либо мысли по этому поводу?

Обновление 2 : есть однозначный-много отношения между классом C и классом B. Hibernate также пытается обнулить поле "c_id" в таблице, соответствующей B, когда я удаляю объект C, который имеет этот c_id.И это, хотя я удаляю объект класса B перед его «родителем».Я знаю, что Hibernate переупорядочивает запросы и добавляет некоторые собственные элементы, но у меня нет смысла переупорядочивать запросы, которые уже находятся в правильном порядке, чтобы они не выполнялись.

Вот (соответствующие части)занятия:

@Entity
@Table(name = "A")
public class A {

    private Set<B> bs;
    private B defaultB;

    @OneToMany(mappedBy = "a", fetch = LAZY)
    public Set<B> getBs() {
        return bs;
    }

    public void setBs(Set<B> bs) {
        this.bs = bs;
    }

    @ManyToOne(fetch = LAZY, optional = false)
    @JoinColumn(name = "default_b_id", nullable = false)
    public B getDefaultB(){
        return defaultB;
    }

    public void setDefaultB(B defaultB) {
        this.defaultB = defaultB;
    }
}

@Entity
@Table(name = "B")
public class B {

    private a;

    @ManyToOne(fetch = LAZY, optional = false)
    @JoinColumn(name = "A_id", nullable = false)
    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

}

Ответы [ 2 ]

2 голосов
/ 18 августа 2010

Я пытаюсь удалить объект типа A и все связанные с ним объекты B в одной и той же транзакции

Для этого необходимо выполнить каскадную операцию REMOVE, если вы не хотитедолжны удалить все Bs вручную.Я бы попробовал следующее (используя cascade для обеих ассоциаций):

@Entity
@Table(name = "A")
public class A {

    private Set<B> bs;
    private B defaultB;

    @OneToMany(mappedBy = "a", fetch = LAZY, cascade=CascadeType.REMOVE)
    public Set<B> getBs() {
        return bs;
    }

    public void setBs(Set<B> bs) {
        this.bs = bs;
    }

    @ManyToOne(fetch = LAZY, optional = false, cascade=CascadeType.REMOVE)
    @JoinColumn(name = "default_b_id", nullable = false)
    public Strategy getDefaultB(){
        return defaultB;
    }

    public void setDefaultB(B defaultB) {
        this.defaultB = defaultB;
    }
}

Я не могу изменить эти аннотации.Кстати, я удаляю все связанные B вручную, просто запросы Hibernate не выполняют то, что я хочу.

Хорошо ... Но тогда я думаю, что вы не обновляете правильно обе стороны двунаправленной ассоциации перед удалением сущностей.Обычно это делается в таких методах защитного программирования, как этот (в A):

public removeFromBs(B b) {
    b.setA(null);
    this.getBs().remove(b);
}
0 голосов
/ 18 августа 2010

Я предполагаю, что вы хотите удалить a, но Hibernate не разрешает это, потому что b все еще ссылается на него?

Поскольку в вашей метамодели не указано каскадное удаление, вам необходимо «разорвать» ссылку b на a перед удалением a. Так что b.setA(null) перед удалением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...