Как автоматически удалить строку в таблице соединений, чтобы избежать ConstraintViolationException?

Кажется, это должен быть довольно простой вопрос или, по крайней мере, иметь простой ответ. Но я действительно не специалист по базам данных, и я все еще довольно далеко от кривой обучения Hibernate. Тем не менее, вот установка:

Рассмотрим однонаправленное отношение «многие ко многим» между двумя сущностями от Foo до Bar:

(простите за возможные опечатки ниже, нижеследующее, очевидно, является упрощением фактического кода)

Фудто.java:

@Entity
@Table(name = "MyDB.dbo.Foo")
class FooDTO implements Serializable
{
    private int id;
    private String name;
    private Set<BarDTO> bars = new HashSet<BarDTO>();

    ...

    @Fetch(FetchMode.JOIN)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "MyDB.dbo.FooBar",
               joinColumns = { @JoinColumn(name = "fooId") },
               inverseJoinColumns = { @JoinColumn(name = "barId") })
    public Set<BarDTO> getBars()
    {
        return bars;
    }
    public void setBars(Set<Bar> bars)
    {
        this.bars = bars;
    }
}

BarDTO.java:

@Entity
@Table(name = "MyDB.dbo.Bar")
class BarDTO implements Serializable
{
    private int id;
    private String name;

    ...
}

На стороне TSQL таблица соединений настроена следующим образом:

CREATE TABLE [dbo].[FooBar](
    [id] [int] NOT NULL IDENTITY PRIMARY KEY,
    [fooId] [int] NOT NULL,
    [barId] [int] NOT NULL,
    CONSTRAINT fk_FooBar_FooId FOREIGN KEY (fooId) REFERENCES [dbo].[Foo](id),
    CONSTRAINT fk_FooBar_BarId FOREIGN KEY (barId) REFERENCES [dbo].[Bar](id),
) ON [PRIMARY]
END

Если я попытаюсь полностью удалить BarDTO, я получу ConstraintViolationException, потому что я не удалил сначала строку в таблице соединений (да).

Вопросы:

  • Могу ли я заставить Hibernate автоматически удалять строки в таблице соединений, когда я удаляю Bar? Как?
  • Если нет, то как мне выбрать все Foo, у которых есть конкретный Bar, чтобы я мог удалить этот Bar из каждого соответствующего набора Foo Bar?

Что касается последнего вопроса, я думаю, что это можно сделать либо с помощью NamedQuery, либо с помощью Criteria API, но я не знаю, как именно написать такой запрос или какие ограничения применить. Я думаю, что именованный запрос будет выглядеть примерно так:

SELECT f FROM FooDTO f INNER JOIN ??? WHERE f.id = ???

но я не уверен, куда пойдет параметр barId или как присоединиться к таблице FooBar, поскольку я не объявляю ее как сущность. (Примечание: я также помню предыдущие проблемы с попыткой присоединиться к именованному запросу — невозможно ли присоединение к именованному запросу?)


person Matt Ball    schedule 15.09.2010    source источник
comment
определены ли в BarDTO get/setFoos?   -  person Mikeb    schedule 15.09.2010
comment
@Mikeb - нет, не так. Отсюда и односторонняя связь.   -  person Matt Ball    schedule 15.09.2010
comment
Я думаю, что либо это, либо отсутствующая аннотация Cascade.   -  person Mikeb    schedule 15.09.2010
comment
@Mikeb - кто-то уже опубликовал ответ о каскадировании, а затем удалил его после того, как я прокомментировал. По сути, каскадирование - это не ответ, поскольку мой вопрос не об удалении всех Foo Bar при удалении Foo. Я просто пытаюсь автоматически отделить Bar от всех Foo, которые заботятся о нем, чтобы я мог удалить Bar.   -  person Matt Ball    schedule 15.09.2010


Ответы (1)


Могу ли я заставить Hibernate автоматически удалять строки в таблице соединений, когда я удаляю панель? Как?

Вам нужно удалить экземпляр BarDTO из коллекций в FooDTO, который содержит ссылку на него.

Если нет, то как мне выбрать все Foos, у которых есть определенный Bar, чтобы я мог удалить этот Bar из каждого соответствующего набора Bars Foo?

Следующее должно работать:

SELECT f FROM FooDTO f WHERE :bar MEMBER OF f.bars 

Или вы можете сделать ассоциацию двунаправленной и просто вызвать bar.getFoos().

person Pascal Thivent    schedule 15.09.2010
comment
Пойдет ли этот HQL в NamedQuery? Например, @NamedQuery(name = "FooDTO.findByBar", query = "SELECT r FROM FooDTO f WHERE :bar MEMBER f.bars") ? Или это должно быть написано как entityManager.createQuery(...)? - person Matt Ball; 15.09.2010
comment
@Bears Как хотите, ничто не мешает использовать этот запрос как именованный запрос. - person Pascal Thivent; 15.09.2010