我在一个项目中使用了几年的时间,从hibernate 4.3.11.Final和spring 4.3.1升级到操纵和持久化对象。最近我迁移到hibernate 5.2.10.Final,遇到了一个描述它的问题。我有两个域类,如下所示:
public class Post extends BaseEntity<Long> {
private String title;
private Set<PostComment> comments = new HashSet<>(0);
// getters and setters removed for brevity
}
public class PostComment extends BaseEntity<Long> {
private Post post;
private String descripton;
// getters and setters removed for brevity
}
public abstract class BaseEntity<T> implements Serializable {
private T id;
}
这些是hibernate映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="" table="tbl_post">
<id name="id" type="long" >
<column name="ID" />
<generator class="sequence" >
<param name="sequence">RGH.SEQ_POST</param>
</generator>
</id>
<property name="title" column="title" type="string" not-null="true" />
<set name="comments" inverse="true" cascade="save-update,merge">
<key>
<column name="post_id" not-null="true" />
</key>
<one-to-many class="com.rgh.PostComment" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="" table="tbl_post_comment">
<id name="id" type="long" >
<column name="ID" />
<generator class="sequence" >
<param name="sequence">RGH.SEQ_POST_COMMENT</param>
</generator>
</id>
<property name="descripton" column="descripton" type="string" not-null="true" />
<many-to-one name="post" column="post_id" entity-name="com.rgh.Post" not-null="true" />
</class>
</hibernate-mapping>
在PostService
类中有两个方法,一个保存Post
实体和它的PostComment
,另一个保存Post
实体并记录它的PostCommment
的计数。
@Service
public class PostService {
@Autowired
private PostRepository repo;
@Autowired
private PostCommentRepository commentRepo;
@Transactional
public Long save() {
Post post = new Post();
post.setTitle("sample post");
repo.save(post);
Set<PostComment> postComments = new HashSet<>();
for (int i = 0 ; i < 3 ; i++) {
PostComment postComment = new PostComment();
postComment.setPost(post);
postComment.setDescription("description " + i);
commentRepo.save(postComment);
}
return post.getId();
}
@Transactional
public int saveAndGetDetailsCount(Post entity) {
entity.setTitle(entity.getTitle() + " updated!");
repo.save(entity);
Post post = repo.loadById(entity.getId());
System.out.println(post.Comments().size());
return post.Comments().size();
}
}
PostRepository
和PostCommentRepository
都是从GenericRepository
扩展而来的,您可以在下面看到:
@Repository
public class PostRepository extends GenericRepository<Post, Long> {
@Override
protected Class<Post> getDomainClass() {
return Post.class;
}
}
@Repository
public class PostCommentRepository extends GenericRepository<PostComment, Long> {
@Override
protected Class<PostComment> getDomainClass() {
return PostComment.class;
}
}
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
try {
return sessionFactory.getCurrentSession();
} catch (Exception e) {
}
return sessionFactory.openSession();
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
session.save(entity);
}
else {
entity = (T)session.merge(entity);
session.update(entity);
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
当我调用save
方法,然后调用saveAndGetDetailsCount
时,一切正常,它更新实体,然后执行select...
查询来加载Post
实体,然后记录3并发布评论。
但在我迁移到hibernate 5.2.10.Final并应用这些更改后:
@Entity
@Table(schema = "RGH", name = "TBL_POST")
@SequenceGenerator(name = "sequence_db", sequenceName = "RGH.SEQ_POST", allocationSize = 1)
public class Post extends BaseEntity<Long> {
@Column
private String title;
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
@Cascade(value = { CascadeType.SAVE_UPDATE, CascadeType.MERGE })
private Set<PostComment> comments = new HashSet<>(0);
// getters and setters removed for brevity
}
@Entity
@Table(schema = "RGH", name = "TBL_POST_COMMENT")
@SequenceGenerator(name = "sequence_db", sequenceName = "RGH.SEQ_POST_COMMENT", allocationSize = 1)
public class PostComment extends BaseEntity<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "POST_ID", nullable = false)
private Post post;
@Column
private String descripton;
// getters and setters removed for brevity
}
public abstract class BaseEntity<T> implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_db")
private T id;
}
然后在GenericRepository
中,我使用EntityManager
获取Session
类,如下所示:
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
/* changed */
@PersistenceContext
private EntityManager em;
public Session getSession() {
/* changed */
return em.unwrap(Session.class);
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
session.save(entity);
}
else {
entity = (T)session.merge(entity);
session.update(entity);
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
现在,问题是,当我在saveAndGetDetailsCount
中运行前面的方法调用时,hibernate不执行select...
查询,并将记录为注释计数。
我想知道为什么会发生这种事。
更新
也许你会问我为什么不使用EntityManager
而不是Session
,因为我使用EntityManager
有一些限制。
更新
当我调用saveAndGetDetailsCount
时,entity
参数只包含id
和title
,在接下来的几行中,您可以看到,我希望加载comments
字段并获取它的大小。
发布于 2018-06-24 02:13:33
你的问题不是迁移到hibernate 5 .I认为你的问题是在同一事务中的transaction.When持久化或合并调用,loadById不会执行,直到方法返回.You可以在保存后刷新以正确工作合并和加载你的对象。
将您的代码更改为以下代码
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
/* changed */
@PersistenceContext
private EntityManager em;
public Session getSession() {
/* changed */
return em.unwrap(Session.class);
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
em.persist(entity);
}
else {
em.merge(entity);
em.flush();
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
发布于 2018-05-23 16:03:04
如果实体已经附加到当前会话,为什么要生成查询?
另外,为什么要调用合并和更新呢?您应该使用其中之一。但不是两个都有。
https://stackoverflow.com/questions/50480790
复制相似问题