jpa标准:treat实体上左连接的querysyntaxexception

dw1jzc5e  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(373)

型号:

@Entity
public class User {

    @Id
    private Integer id;

    @JoinColumn(name = "user_id")
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Project> projects;
}
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Type")
public abstract class Project {

    @Id
    private Integer id;

    private String name;
}
@Entity
@DiscriminatorValue("Administrative")
public class AdminProject extends Project {

    private String departmentName;
}
@Entity
@DiscriminatorValue("Design")
public class DesignProject extends Project {

    private String companyName;
}

我正在尝试使用jpa的criteriaapi来查询 User 基于实现的属性的实体 Project . 例如,查询具有“some\ u name”department(该字段在上不存在)项目的所有用户 DesignProject ).
我看到有一种方法可以通过对 Project 查询的实体。我正在尝试类似的方法:

CriteriaBuilder cb...
Root<User> userRoot...
root = ((From) root).join("projects", JoinType.LEFT);
root = cb.treat(root, AdminProject.class);
root = root.get("departmentName");

例外情况:
org.springframework.dao.invaliddataaccessapiusageexception:org.hibernate.hql.internal.ast.querysyntaxexception:无效路径:“generatedalias2.departmentname”[从io.github.influsehub.rsql.model.user中选择generatedalias0作为generatedalias0左连接generatedalias0.projects作为generatedalias1 where treat(generatedalias2作为io.github.hub.rsql.model.adminproject).departmentname=:param0];嵌套异常为java.lang.illegalargumentexception:org.hibernate.hql.internal.ast.querysyntaxexception:invalid path:'generatedalias2.departmentname'[从io.github.implesshub.rsql.model.user选择generatedalias0作为generatedalias0 left join generatedalias0.projects作为generatedalias1 where treat(generatedalias2作为io.github.hub.rsql.model.adminproject).departmentname=:param0]
我错过了什么?是与连接有关,还是之后的向下转换是如何发生的?

编辑

在@k.nicholas的回答之后,我设法使查询在一个单独的场景中工作,但在我的应用程序中没有。但是,我注意到 entityManager.createQuery(query) call在第一次调用时抛出上面的异常,如果我再次调用它而不更改查询对象,它就会工作。下面是第二次调用时生成的查询(此查询从数据库中查找所需的对象):
从用户中选择generatedalias0作为generatedalias0 left join generatedalias0.projects作为generatedalias2 where treat(generatedalias2作为io.github.implessHub.rsql.model.adminproject)。部门名称=:param0
为什么实体管理器在连续调用两次时会创建两个不同的查询?

d5vmydt9

d5vmydt91#

我会做的 Entitys 有点不同,你会看到的。主要的问题是你正在使用 User 作为你的根,加入一个 Projects . 这是一个问题,因为您应该在 Project 分类并使用 projects 字段作为仅查询字段。我就是这么做的。这样效果更好。这也是一个问题,因为你必须做一个 join fetch 而不是 join 所以 projects 把它带走 users .
首先,实体是这样的:

@Entity
public class User { 
    @Id
    private Integer id; 
    @OneToMany(mappedBy="user")
    private List<Project> projects;
}

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Type")
public abstract class Project {
    @Id
    private Integer id;
    private String name;    
    @ManyToOne
    private User user;
}

@Entity
@DiscriminatorValue("Administrative")
public class AdminProject extends Project {
    private String departmentName;
}

@Entity
@DiscriminatorValue("Design")
public class DesignProject extends Project {    
    private String companyName;
}

经过一番挖掘,我发现了一个jpql查询可以实现这个功能。这是一个起点:

List<User> users = entityManager.createQuery("select distinct(u) from User u join fetch u.projects p where TYPE(p) = 'Administrative' and p.departmentName = 'dept1'", User.class).getResultList();

经过进一步的挖掘,我发现 treat 如果你做得正确的话,它工作得很好,而且对于jpa2.1你应该使用 EntityGraph 一定要拿到钱 join 做某事 fetch .

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = builder.createQuery(User.class);
Root<User> root = query.from(User.class);
Join<User, Project> join = root.join("projects");
query.select(root).where(builder.equal(builder.treat(join, AdminProject.class).get("departmentName"), "dept1"));
EntityGraph<User> fetchGraph = entityManager.createEntityGraph(User.class);
fetchGraph.addSubgraph("projects");
users = entityManager.createQuery(query.distinct(true)).setHint("javax.persistence.loadgraph", fetchGraph).getResultList();

顺便说一下,生成的查询略有不同,但我没有仔细研究它们。你应该。

相关问题