如何自动删除连接表中的行以避免 ConstraintViolationException?
这看起来应该是一个非常简单的问题,或者至少有一个简单的答案。但是 - 我真的不是一个数据库专家,而且我在 Hibernate 学习曲线上还远远落后。也就是说,设置如下:
考虑两个实体之间的单向多对多关系,从 Foo
到 Bar
:
(请原谅下面的任何拼写错误,以下显然是实际代码的简化)
FooDTO.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
因为我没有首先删除连接表中的行(废话)。
问题:
- 当我删除
Bar
时,我可以让 Hibernate 自动删除连接表中的行吗?如何? - 如果没有,我如何选择具有特定
Bar
的所有Foo
,以便我可以从每个相关中删除该
的一组Bar
FooBar
?
关于后一个问题,我认为这可以通过 NamedQuery 或使用 Criteria API 来完成,但我不知道具体如何编写这样的查询或应用哪些约束。我认为命名查询看起来像这样:
SELECT f FROM FooDTO f INNER JOIN ??? WHERE f.id = ???
但我不确定 barId
参数会去哪里,或者如何加入 FooBar
表,因为我不知道不要将其声明为实体。 (旁注,我还记得以前尝试加入命名查询时遇到的问题 - 加入命名查询不可能吗?)
This seems like it should be a pretty simple question, or at least have a simple answer. But - I'm really not a database guy, and I'm still pretty far down on the Hibernate learning curve. That said, here's the setup:
Consider a unidirectional many-to-many relationship between two entities, from Foo
to Bar
:
(pardon any typos below, the following is obviously a simplification of the actual code)
FooDTO.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;
...
}
On the TSQL side, the join table is set up like this:
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
If I try to outright delete a BarDTO
, I get a ConstraintViolationException
because I haven't first deleted the row in the join table (duh).
Questions:
- Can I get Hibernate to drop the rows in the join table automagically, when I delete a
Bar
? How? - If not, how do I select all the
Foo
s that have a particularBar
, so I can remove thatBar
from each relevantFoo
's set ofBar
s?
With regard to the latter question, I think this could be done with either a NamedQuery
or using the Criteria API, but I don't know specifically how to write such a query or which constraints to apply. I think it would a named query would look something like:
SELECT f FROM FooDTO f INNER JOIN ??? WHERE f.id = ???
but I'm not sure where the barId
parameter would go, or how to join on the FooBar
table since I don't declare it as an entity. (Side note, I also recall previous issues with trying to join in a named query - is joining in a named query impossible?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要从
FooDTO
中包含其引用的集合中删除BarDTO
实例。以下应该可行:
或者您可以使关联成为双向并简单地调用
bar.getFoos()
。You need to remove the
BarDTO
instance from the collections inFooDTO
that holds a reference on it.The following should work:
Or you could make the association bidirectional and simply call
bar.getFoos()
.