sha*_*ltc 19 java hibernate jpa
我有两个实体:UserAccount和Notification.这些关系如下所示.
public class UserAccount {
@Id
@Column(name = "USER_NAME")
private String emailId;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "USERS_NOTIFICATIONS", joinColumns = { @JoinColumn(name = "USER_NAME") }, inverseJoinColumns = { @JoinColumn(name = "NOTIFICATION_ID") })
private List<Notification> notifications;
//setters, getter, equals and hashcode
}
Run Code Online (Sandbox Code Playgroud)
既equals()和hashcode()被覆盖(通过与业务键/主键IDE生成).
给定a UserAccount,当我添加第一个时Notification,它会产生一个INSERT语句.但是在进一步添加时UserAccount,它首先删除然后插入:
Hibernate: delete from USERS_NOTIFICATIONS where USER_NAME=?
Hibernate: insert into USERS_NOTIFICATIONS (USER_NAME, NOTIFICATION_ID) values (?, ?)
Hibernate: insert into USERS_NOTIFICATIONS (USER_NAME, NOTIFICATION_ID) values (?, ?)
Hibernate: insert into USERS_NOTIFICATIONS (USER_NAME, NOTIFICATION_ID) values (?, ?)
//as many inserts as the notifications the user has
Run Code Online (Sandbox Code Playgroud)
每一个都发生同样的事情UserAccount.如果我更换List用Set,出现正常的INSERT.我在阅读本文档和博客后找到了原因.
来自文档的观察
@OneToMany关联中,Set是优选的.应该清楚的是,索引
Collections并Sets允许在添加,删除和更新元素方面进行最有效的操作.
@OneToMany关系(@ManyToOne管理)中,List并且Bags是有效的.
Bags并且Lists是最有效的逆Collections.
话虽如此,更可取的是:
一个Set在List一个单向@OneToMany映射?
或者,我是否必须通过添加双向关系来调整我的域模型以使用a List,尤其是当存在重复时?
kwi*_*atz 11
不久前我遇到了这个问题......
我发现这篇文章:Hibernate中一对多关联的性能反模式https://fedcsis.org/proceedings/2013/pliks/322.pdf
简而言之:
List/ Collection+ @OneToMany- >添加了一个元素:1个删除,N个插入,删除了一个元素:1个删除,N个插入List+ @OneToMany+ @IndexColumn/ @OrderColumn- >添加了一个元素:1个插入,M个更新,删除了一个元素:1个删除,M个更新Set+ @OneToMany- >添加一个元素:1个插入,删除一个元素:1删除对我来说:是的,这意味着你必须改变你List对Set单向@OneToMany.所以我改变了我的模型以符合Hibernate的期望,这导致了很多问题,因为应用程序的视图部分List主要依赖于......
一方面,这Set对我来说是一个合乎逻辑的选择,因为没有重复,另一方面List更容易处理.
所以JPA/Hibernate强迫我改变模型对象,这不是第一次,当你使用时,@EmbededId你做了一些你可能不会在没有JPA/Hibernate的情况下做同样的事情.当你必须要注意HibernateProxy所有的应用程序,尤其是equals方法else if(object instanceof HibernateProxy) {......时,你会注意到JPA/Hibernate persitence层在其他层中有点干扰.
但是,当我使用directely JDBC时,我也会使用更改模型或商务方法来促进持久性...层次隔离可能是一个梦想或成本太高而不能100%完成?
Set如果它们与注释SortedSet一样TreeSet,您可以订购@OrderBy
这带来一个问题,当一些代码依赖List,不能改变(如JSF/PrimeFaces <dataTable>或<repeat>组件),所以你必须改变你的Set进入List和返回Set,但如果你这样做setNotifications(new HashSet<>(notificationList)),你将有额外的查询,因为该集是org.hibernate.collection.PersistentSet由Hibernate管理...所以我使用addAll()而removeAll()不是setter:
protected <E> void updateCollection(@NonNull Collection<E> oldCollection, @NonNull Collection<E> newCollection) {
Collection<E> toAdd = new ArrayList<>(newCollection) ;
toAdd.removeAll(oldCollection) ;
Collection<E> toRemove = new ArrayList<>(oldCollection) ;
toRemove.removeAll(newCollection) ;
oldCollection.removeAll(toRemove) ;
oldCollection.addAll(toAdd) ;
}
Run Code Online (Sandbox Code Playgroud)
记住你的方法equals()和hashCode()方法@Entity......
另一个问题是你需要掌握JPA和Hibernate,如果你想使用JPA和Hibernate作为实现,因为Set/List/Bag语义来自Hibernate而不是来自JPA(如果我错了,请纠正我)
规范用于将实现抽象为不依赖于特定供应商.尽管大多数JavaEE规范都成功了,但JPA对我来说失败了,而且我放弃了独立于Hibernate
列表:允许其中有重复的元素。
Set:所有元素都应该是唯一的。
现在,删除可能会发生,因为您覆盖了列表中的元素,因此当您修改 UserAccount 类型的持久实体时,它会删除先前在列表中的实体。
| 归档时间: |
|
| 查看次数: |
19556 次 |
| 最近记录: |