Tho*_*mas 5 java mapping hibernate jpa readonly
是否可以在 hibernate / jpa 中创建在获取包含实体时获取的关系,但在保存包含实体时永远不会导致任何数据库更新?我将尝试通过一个例子来阐明要求。
我有一个简单的实体 B
@Entity
public class B {
private int bId;
@Id
public int getBId() {
return bId;
}
public void setBId(int aId) {
bId = aId;
}
}
Run Code Online (Sandbox Code Playgroud)
另一个实体 A,包含到该类的单向多对多映射。
@Entity
public class A {
private int aId;
private List<B> bs;
@Id
public int getAId() {
return aId;
}
public void setAId(int aId) {
this.aId = aId;
}
@ManyToMany
@JoinTable(name = "A_B",
joinColumns = {@JoinColumn(name = "AID")},
inverseJoinColumns = {@JoinColumn(name = "BID")}
)
public List<B> getBs() {
return bs;
}
public void setBs(List<B> aBs) {
bs = aBs;
}
}
Run Code Online (Sandbox Code Playgroud)
当实体 A 从数据库中获取并随后合并时,如下所示
A a = em.find(A.class, 1);
a.getBs().size();
em.merge(a);
Run Code Online (Sandbox Code Playgroud)
,合并结果为以下 SQL 语句
Hibernate:
delete
from
A_B
where
AID=?
Hibernate:
insert
into
A_B
(AID, BID)
values
(?, ?)
Hibernate:
insert
into
A_B
(AID, BID)
values
(?, ?)
Run Code Online (Sandbox Code Playgroud)
我必须避免这些删除+更新。对于我的应用程序,我可以确保永远不会使用 hibernate 更新映射表。无论如何,都需要更新包含的实体。
所以我的问题是:是否可以映射此类“只读”集合并避免数据库更改?
此致
托马斯
更新:
这些是我正在使用的表格和数据:
CREATE TABLE A (
AID INTEGER NOT NULL
)
DATA CAPTURE NONE ;
CREATE TABLE B (
BID INTEGER NOT NULL
)
DATA CAPTURE NONE ;
CREATE TABLE A_B (
AID INTEGER NOT NULL,
BID INTEGER NOT NULL
)
DATA CAPTURE NONE ;
INSERT INTO A (AID) VALUES (1);
INSERT INTO B (BID) VALUES (1);
INSERT INTO B (BID) VALUES (2);
INSERT INTO A_B (AID, BID) VALUES (1, 1);
INSERT INTO A_B (AID, BID) VALUES (1, 2);
Run Code Online (Sandbox Code Playgroud)
此外,在执行合并之前还需要初始化集合:
a.getBs().size();
Run Code Online (Sandbox Code Playgroud)
注意:我也将上面的行添加到原始帖子中。
正如评论中所写,我最初无法重现该行为。在不改变 集合的情况下B,Hibernate 只是更新 A,而保持连接表不变。但是,通过更改集合Bs(例如添加B),我可以获得 DELETE then INSERT 行为。我不知道这是否说明了您的情况,但这是我的解释......
当使用 aCollection或List 不使用a @IndexColumn(或 a @CollectionId)时,您会得到Bag 语义及其所有缺点:当您删除元素或更改集合时,Hibernate 首先删除所有元素,然后插入(它无法维护顺序)。
因此,为了避免这种行为,请使用:
设置语义(即Set,如果不需要 a ,则使用 a List,这对于 95% 的情况都是如此)。
带主键的包语义(即使用 aList和 a@CollectionId) -我没有测试这个。
true列表语义(即,如果您使用的是 JPA 2.0,则使用 aList与 a@org.hibernate.annotations.IndexColumn或 JPA 2.0 等效项)@OrderColumn
如果您不需要List. 如果您这样做,我只测试了选项 3(感觉更自然),您可以像这样实现(需要额外的列和连接表中的 (B_ID, BS_ORDER) 的唯一约束):
@Entity
public class A {
private int aId;
private List<B> bs;
@Id
public int getAId() { return aId; }
public void setAId(int aId) { this.aId = aId; }
@ManyToMany
@JoinTable(name = "A_B",
joinColumns = {@JoinColumn(name = "AID")},
inverseJoinColumns = {@JoinColumn(name = "BID")}
)
@org.hibernate.annotations.IndexColumn(name = "BS_ORDER")
public List<B> getBs() { return bs; }
public void setBs(List<B> aBs) { bs = aBs; }
}
Run Code Online (Sandbox Code Playgroud)
Hibernate 将BS_ORDER根据需要在更新/删除Bs.
我修改了我的测试代码并切换到 Set 作为 List 的替代品。由于此更改,只要集合保持不变,就不再生成删除和更新语句。不幸的是,我的项目中有条件,集合被修改。因此,我要求一个只读语义,其中休眠从数据库加载映射数据但不保存任何更改,这可能已对集合进行。
是的,我知道这就是您所要求的,但是:
我认为您关心的是删除然后插入,您问题的“只读部分”看起来像是真正问题的丑陋解决方法。
“额外”的要求,即不保存已修改的持久集合的状态(这是不寻常的,当您有一个持久集合时,如果您修改其状态,您通常希望保存它)不清楚,至少不是为我。
无论如何...关于第二点,Hibernate 的@Immutable注释不适合这里(它不允许所有修改,如果有则抛出异常)。但也许您可以处理集合的临时副本,而不是修改持久副本?
| 归档时间: |
|
| 查看次数: |
4354 次 |
| 最近记录: |