繁体   English   中英

Hibernate:查询未映射的 class

[英]Hibernate: Query unmapped class

我有两个实体,我使用 REST、Hibernate 和 Postgres 实现 CRUD 操作。 API 是用 Quarkus 编写的。

有一个租户和一个成员 class。

会员 class

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@Entity(name = "member")
@Table(name = "member")
public class Member {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    private UUID id;

    @Column(name = "name", length = 50, unique = true, nullable = false)
    private String name;

}

租户 class:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity(name = "tenant")
@Table(name = "tenant")
public class Tenant {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    @Column(length = 50, unique = true, nullable = false)
    private String name;

    @Column(name = "display_name", length = 50, unique = true, nullable = false)
    private String displayName;

    @JsonInclude(Include.NON_NULL)
    @Column(length = 140, nullable = true)
    private String description;

    @JsonInclude(Include.NON_NULL)
    @Column(name = "delete_after", nullable = true)
    private Timestamp deleteAfter;

    @OneToOne
    @JoinColumn(name = "owner", nullable = false, unique = false)
    private Member owner;

    @ManyToMany(fetch = FetchType.EAGER)
    private List<Member> members;
    
    public void addMember(Member member) {
        if(members == null)
            members = new ArrayList<>();

        if (!members.contains(member))
            members.add(member);
    }
}

如您所见,租户可以有许多成员。 Hibernate 为这两个类创建了三个表:

           List of relations
 Schema |     Name      | Type  |  Owner   
--------+---------------+-------+----------
 public | member        | table | postgres
 public | tenant        | table | postgres
 public | tenant_member | table | postgres

postgres=# select * from member;
                  id                  | name 
--------------------------------------+------

postgres=# select * from tenant;
                  id                  | delete_after | description | display_name |   name   |                owner                 
--------------------------------------+--------------+-------------+--------------+----------+--------------------------------------

postgres=# select * from tenant_member;
              tenant_id               |              members_id              
--------------------------------------+--------------------------------------

我的用例是我想获取在其成员列表中具有特定成员的所有租户。

在命令行中,这将起作用:

SELECT t FROM tenant t WHERE t.id in (SELECT m.tenant_id FROM tenant_member m WHERE m.members_id = '137e86ce-fb75-4224-87a3-652e8a1d7cff' );

不幸的是,当我将此查询放入我的代码时,我遇到了一个问题:

public List<Tenant> getAllTenantByMember(@PathParam("memberId") UUID memberId) {
  
        Member member = entityManager.find(Member.class, memberId);
        if(member == null)
            throw new NotFoundException("Owner not found.");
        TypedQuery<Tenant> query = entityManager.createQuery("SELECT t FROM tenant t WHERE t.id in (SELECT m.tenant_id FROM tenant_member m WHERE m.members_id = :value )", Tenant.class);
        query.setParameter("value", memberId);
            

        List<Tenant> result = query.getResultList();
        return result != null ? result : new ArrayList<Tenant>();
    }

具体问题是一个例外:

2021-02-17 00:34:14,933 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /api/v1/members/137e86ce-fb75-4224-87a3-652e8a1d7cff/tenants failed, error id: 33c184bd-6f42-4db8-9439-361642cad8e3-1: org.jboss.resteasy.spi.UnhandledException: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: tenant_member is not mapped [SELECT t FROM mypackage.orm.Tenant t WHERE t.id in (SELECT m.tenant_id FROM tenant_member m WHERE m.members_id = :value )]
    at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)
    at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:138)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:41)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:93)
    at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:231)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2415)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at java.base/java.lang.Thread.run(Thread.java:834)
    at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: tenant_member is not mapped [SELECT t FROM mypackage.orm.Tenant t WHERE t.id in (SELECT m.tenant_id FROM tenant_member m WHERE m.members_id = :value )]
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:725)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:816)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:113)
    at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.createQuery(TransactionScopedSession.java:379)
    at io.quarkus.hibernate.orm.runtime.session.ForwardingSession.createQuery(ForwardingSession.java:188)
    at io.quarkus.hibernate.orm.runtime.session.ForwardingSession.createQuery(ForwardingSession.java:47)
    at mypackage.resources.MemberResource.getAllTenantByMember(MemberResource.java:79)
    at mypackage.resources.MemberResource_Subclass.getAllTenantByMember$$superaccessor2(MemberResource_Subclass.zig:440)
    at mypackage.resources.MemberResource_Subclass$$function$$2.apply(MemberResource_Subclass$$function$$2.zig:33)
    at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
    at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:127)
    at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:100)
    at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:32)
    at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:53)
    at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:26)
    at io.quarkus.narayana.jta.runtime.interceptor.TransactionalInterceptorRequired_Bean.intercept(TransactionalInterceptorRequired_Bean.zig:340)
    at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
    at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
    at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
    at mypackage.resources.MemberResource_Subclass.getAllTenantByMember(MemberResource_Subclass.zig:397)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:643)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:507)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:457)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:459)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:419)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:393)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:68)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
    ... 18 more
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: tenant_member is not mapped [SELECT t FROM mypackage.orm.Tenant t WHERE t.id in (SELECT m.tenant_id FROM tenant_member m WHERE m.members_id = :value )]
    at org.hibernate.hql.internal.ast.QuerySyntaxException.generateQueryException(QuerySyntaxException.java:79)
    at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:220)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162)
    at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:604)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:716)
    ... 52 more
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: tenant_member is not mapped
    at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:169)
    at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:91)
    at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromClause.java:77)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.java:333)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3758)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3647)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:732)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:588)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.collectionFunctionOrSubselect(HqlSqlBaseWalker.java:4993)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.inRhs(HqlSqlBaseWalker.java:4893)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4554)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2161)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:827)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:621)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:325)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:273)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192)
    ... 58 more

有人知道如何处理错误或者可能知道另一种创建查询的方法,其中 where 条件是列表中的 object?

您的问题是您尝试在entityManager.createQuery方法中混淆JPQLSQL语法。

尝试使用以下查询:

TypedQuery<Tenant> query = entityManager.createQuery("SELECT t FROM tenant t 
join t.members m where m.id = :value", Tenant.class);
query.setParameter("value", memberId);
List<Tenant> result = query.getResultList();

我建议您从所有@Entity注释中删除name属性,并在您的 JPQL 中使用 class 名称,如下所示:

SELECT t FROM Tenant t 
join t.members m where m.id = :value

这是常见的做法,它可以让您强调这是 JPQL,而不是 SQL 查询。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM