具有分离实体的JPA成员查询

时间:2012-01-04 15:13:02

标签: hibernate jpa orm jpa-2.0

我想做一个简单的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;
}

2 个答案:

答案 0 :(得分:1)

当事务提交时,持久化上下文中的所有对象都与底层数据库同步。因此,当您设置实体管理器检索的对象时工作正常,因为对象处于托管状态。

在这里,您正在创建一个新对象&amp;将其设置为事务中查询的参数,会导致异常,因为对象已分离。

来自文档:

  

当用户将瞬态实例传递给Session方法时抛出   期望一个持久的实例。

答案 1 :(得分:1)

正如Nayan Wadekar所说,:memberParameter MEMBER OF i.tags需要一个持久的实例。

所以这里有两种解决方案。

  1. 确保传入Tag对象的已持久实例。
  2. 如果你不能这样做,你可以通过JOIN查询通过'tag'-name查询:

    SELECT i FROM ItemDescription i JOIN c.tags t
    WHERE t.name LIKE :name