1

JPA基準APIを使用して「IN」クエリを作成しています。特定のカテゴリにあるコースを選択したい。カテゴリは、クエリの IN 部分で終わるはずです。

これは Course エンティティです。各コースは 1 つのカテゴリにあるため、カテゴリ エンティティへの参照があります。

@Entity
public class Course implements DomainObject {

private Long id;
private Integer version;
private String name;
private Category category;


@Override
@Id
@GeneratedValue
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

@ManyToOne
public Category getCategory() {
    return category;
}

public void setCategory(Category category) {
    this.category = category;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getVersion() {
    return version;
}

public void setVersion(Integer version) {
    this.version = version;
}

}

私のサービスでは、特定の (リスト) カテゴリに属する​​コースを選択したいと考えています。

public List<Course> findCourses(CourseFilter filter) {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Course> criteriaQuery = criteriaBuilder.createQuery(Course.class);
    Root<Course> root = criteriaQuery.from(Course.class);
    List<Predicate> predicateList = new ArrayList<Predicate>();

    if (!filter.getCategories().isEmpty()) {
        Predicate predicate = root.get(Course_.category).in(filter.getCategories());
        predicateList.add(predicate);
    }

    Predicate[] predicates = new Predicate[predicateList.size()];
    predicateList.toArray(predicates);

    criteriaQuery.where(predicates);
    TypedQuery<Course> typedQuery = entityManager.createQuery(criteriaQuery);

    return typedQuery.getResultList();
}

メソッドの最後の行でクエリを実行すると、エラーがスローされます。

HTTP Status 500 - Request processing failed; nested exception is
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientObjectException: object references an unsaved transient instance
save the transient instance before flushing:nl.codebasesoftware.produx.domain.Category;
nested exception is java.lang.IllegalStateException:
org.hibernate.TransientObjectException: object references an unsaved transient instance
save the transient instance before flushing: nl.codebasesoftware.produx.domain.Category

IN クエリを作成する正しい方法を使用しているかどうかさえわかりません。クライテリア API は非常に複雑だと思います。しかし、IN クエリについて心配する前に、Hibernate がこの TransientObjectException をスローする理由を知りたいと思います。filter.getCategories()呼び出しの結果は、主キー ID などで埋められた実際のカテゴリになります。

追加した:

後で Courses を取得するために使用する Category インスタンスを取得する方法を次に示します。これは、@Controller メソッドから @Service を介して呼び出される DAO メソッドでもあります。

public Category findByName(String name) {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Category> query = builder.createQuery(Category.class);
    Root<Category> root = query.from(Category.class);
    Predicate predicate = builder.equal(root.get(Category_.urlTitle), name);
    query.where(predicate);
    TypedQuery<Category> typedQuery = entityManager.createQuery(query);
    return getSingleResult(typedQuery);
}

そのため、Hibernate は、保存されていないエンティティを何らかの方法で参照する Category オブジェクトを使用していると言っていますが、その方法がわかりません。このメソッドから返されるカテゴリは、Hibernate によってフェッチされた場合の単なるカテゴリです。コースをフェッチするメソッドに送信する前に、何もしていません。

これが私のコントローラーメソッドです:

@RequestMapping(method = RequestMethod.GET, value = "/{categoryUrlName}")
public String setup(@PathVariable("categoryUrlName") String categoryUrlName, Model model){
    // Fetch the category
    Category category = categoryService.findByName(categoryUrlName);

    // if no category found, throw a 404
    if(category == null){
        throw new ResourceNotFoundException();
    }
    // Fetch courses in this category
    List<Course> courses = courseService.findCourses(category);

    model.addAttribute("courses", courses);
    model.addAttribute("category", category);
    model.addAttribute("mainContent", "content/category");
    return "main";
}
4

1 に答える 1

1

クエリを実行する前に、Hibernate はセッションで永続エンティティに加えた変更をフラッシュします。これにより、クエリがすべてのエンティティの最新の状態を検索することが保証されます。残念ながら、Hibernate がフラッシュしようとするダーティ エンティティの 1 つが一時エンティティを参照しているため、フラッシュできず、例外が発生します。例外は、クエリ自体からではなく、クエリの実行前のフラッシュから発生します。

クエリを実行する前に、次のようなことを行った可能性があります。

Cat cat = em.find(Cat.class, catId); // cat is a persistent persistent entity
cat.setMate(new Mouse()); // the mouse has not been persisted, and cat references it.
于 2012-09-18T21:50:33.850 に答える