我想做一个简单的JPA会员查询,但我不能为我的生活让它工作。 Hibernate抛出一个TransientObjectException,消息“object引用一个未保存的瞬态实例 - 在刷新之前保存实例:Tag”。查询如下:
public Collection<ItemDescription> getItems(){
String entityClass = "ItemDescription";
TypedQuery<ItemDescription> query = entityManager.createQuery(
"SELECT i FROM " + entityClass +" i " +
"WHERE :tag MEMBER OF i.tags", ItemDescription.class);
query.setParameter("tag", new Tag("category:test"));
List<ItemDescription> resultList = query.getResultList();
return resultList;
}
两个实体类如下所示:
@Entity
@Table(name = "tags")
public class Tag extends AbstractDomainEntity {
private static final long serialVersionUID = 2632379096725992272L;
private String value;
...
}
@Entity
@Table(name = "itemdescriptions")
public class ItemDescription extends AbstractDomainEntity {
private static final long serialVersionUID = 9164310940207023539L;
private Set<Tag> tags = new HashSet<Tag>();
...
@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL, orphanRemoval = true)
public Set<Tag> getTags() {
return tags;
}
private void setTags(Set<Tag> tags) {
this.tags = tags;
}
}
当我使用从实体管理器检索的Tag对象作为查询参数时,同样的查询有效。 “tag”参数真的必须是一个托管实体吗?为什么?如何让查询起作用?谢谢你们的帮助!
[编辑:] 谢谢你的提示。我现在最终得到了这个查询:
public Collection<ItemDescription> getItems(){
String entityClass = "ItemDescription";
TypedQuery<ItemDescription> query = entityManager.createQuery(
"SELECT i FROM " + entityClass +" i " +
"JOIN i.tags t " +
"WHERE t.value = :tag", ItemDescription.class);
query.setParameter("tag", "category:test");
List<ItemDescription> resultList = query.getResultList();
return resultList;
}
答案 0 :(得分:1)
当事务提交时,持久化上下文中的所有对象都与底层数据库同步。因此,当您设置实体管理器检索的对象时工作正常,因为对象处于托管状态。
在这里,您正在创建一个新对象&amp;将其设置为事务中查询的参数,会导致异常,因为对象已分离。
来自文档:
当用户将瞬态实例传递给Session方法时抛出 期望一个持久的实例。
答案 1 :(得分:1)
正如Nayan Wadekar所说,:memberParameter MEMBER OF i.tags
需要一个持久的实例。
所以这里有两种解决方案。
如果你不能这样做,你可以通过JOIN查询通过'tag'-name查询:
SELECT i FROM ItemDescription i JOIN c.tags t
WHERE t.name LIKE :name