当前位置: 首页 > 知识库问答 >
问题:

JPA标准:treat实体上左连接的QuerySyntaxException

冯飞鹏
2023-03-14

型号:

@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的条件api根据Project实现的属性查询User实体。例如,查询所有拥有“SOME_NAME”部门项目的用户(该字段在DesignProject上不存在)。

我发现有一种方法可以通过向下转换查询的项目实体来实现。我正在尝试类似的方法:

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.QuerySyn郊外:无效路径:生成一个lias2.department名称[选择生成Alias0从io.github.perplexhub.rsql.model.用户作为生成Alias0左连接生成lias0.projects作为生成Alias1在哪里对待(生成Alias2作为io.github.perplexhub.rsql.model.AdminProject). departmentName=: Param0];嵌套异常是java.lang.IllegalArgumentException:org.hibernate.hql.internal.ast.查询语法异常:无效路径:生成lias2.department名称[选择生成Alias0从io.github.perplexhub.rsql.model.用户作为生成Alias0左连接生成lias0.projects作为生成Alias1在哪里对待(生成Alias2作为io.github.perplexhub.rsql.model.AdminProject). departmentName=: Param0]

我错过了什么?这是否与连接有关,或者之后如何进行向下投射?

在@K. Nicholas的回答之后,我设法使查询在一个孤立的场景中工作,但在我的应用程序上不工作。但是,我注意到entityManager.createQuery(查询)调用在第一次调用时抛出上面的异常,如果我在不更改查询对象的情况下再次调用它,它就会工作。这是第二次调用时生成的查询(此查询从数据库中找到我想要的对象):

从用户中选择generatedAlias0作为generatedAlias0 left join generatedAlias0。将项目作为generatedAlias2进行处理(generatedAlias2作为io.github.EmploysHub.rsql.model.AdminProject)。部门名称=:param0

为什么连续调用两次时,实体管理器会创建两个不同的查询?

共有1个答案

桑坚
2023-03-14

正如您将看到的那样,我会对实体做一些不同的操作。主要问题是,您正在使用用户作为根用户,并将其加入到项目列表中。这是一个问题,因为您应该在项目类上使用外键,并将项目字段用作仅查询字段。这就是我所做的。这样效果更好。这也是一个值得关注的问题,因为您必须执行加入获取,而不是加入,以便项目与用户一起获取。

因此,首先,实体是这样的:

@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(治疗)可以很好地工作,而在JPA 2.1中,你应该使用EntityGraph(实体图)来获取连接。

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();

作为旁注,生成的查询略有不同,但我没有仔细观察它们。你应该。

 类似资料:
  • 两个数据库表具有外键关系。 它们通过JPA映射到两个实体A和B,但是连接列是从实体中手动删除的,因此在JPA世界中,类A和B是不相关的,您不能通过字段/属性从一个类导航到另一个类。 使用JPA标准API,是否可以创建连接两个表的查询? 我在互联网上找到的所有示例都使用join列来实现目标,但如上所述,它已从代码中删除,因为大多数时候我对A和B之间的关系不感兴趣,而且我担心可能的开销。

  • 尝试编写一个标准api查询。 应该作为参数传递,并且可以更改。我在代码中添加了实体。 感谢任何帮助或指导。 这就是我目前的情况: 我现在能够获取正确的数据,但列表没有排序。这是我在日志中看到的,生成了两个查询,一个有顺序,另一个没有顺序。

  • 我使用JPA2.1、Spring数据和CriteriaBuilder、谓词对我的JPA实体进行查询。我有一个父实体InvoiceSummary,它与名为ShipmentStop的子实体有@OneToMany关系。我想在子实体ShipmentStop上设置条件,但不确定如何进行。我还希望能够同时在父表和子表上设置条件。有没有一种方法可以使用谓词来实现这一点?例如,我想按子实体的departureDa

  • 此查询用于检索一对多关系中的最后记录(请参阅SQL连接:选择一对多关系中的最后记录) 我的问题是:如何使用jpa criteria api使用subselect构建这个连接?可能吗?如果没有,可以使用jpql吗? 到目前为止我的代码:

  • 我正在努力使用jpa Crudepository接口连接两个实体模型。我不知道如何映射两个实体模型并在@query注释中编写查询。这些是我的实体类。我想执行这个查询“从taxi\u driver\u映射中选择dppd.payment\u plan\u id,dppd.attribute\u value,dppd.attribute\u id作为tdm加入driver\u payment\u pla

  • 这是我的命名查询: @NamedQuery(name=“User.findOneWithLists”,query=“从用户u中选择u”“左连接获取u.aTemplates”“左连接获取u.bTemplates”“左连接获取u.bp”“左连接获取u.aCredentials”“左连接获取u.st WHERE(st.deleted=false)”“左连接获取u.bCredentials”“左连接获取u