JPA 查询对不在查询中的列抛出“未找到”错误

Posted

技术标签:

【中文标题】JPA 查询对不在查询中的列抛出“未找到”错误【英文标题】:JPA query is throwing a 'not found' error for column that isn't in query 【发布时间】:2021-07-04 15:50:12 【问题描述】:

我试图只调用我的数据库中的特定列,但查询抛出一个错误,指出未找到下一列(即使它不在查询中)

执行此操作的连接有问题吗?我对这个问题有点困惑。

来自 ConnectionRequestRepository 的 JPA 查询 -

@Query(value = "SELECT connection_request.id, connection_request.userId, connection_request.dateTimeCompleted, connection_request.phoneNumber " +
        "FROM ***.connection_request " +
        "INNER JOIN ***.user " +
        "ON ***.connection_request.userID = ***.user.id " +
        "WHERE connection_request.dateTimeCompleted IS NULL " +
        "LIMIT 1", nativeQuery = true)
ConnectionRequest findActiveRequest();

服务-

public ConnectionRequest getActiveRequestToCaller() 
   return connectionRequestRepository.findActiveRequest();

控制器 -

ConnectionRequest currentLocationRequest = connectionRequestService.getActiveRequestToCaller();

ConnectionRequest 类 -

@Entity
@Table(name = "connection_request")
public class ConnectionRequest 

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
@NotNull
private Long id;
@Column(name = "userId")
@NotNull
private Long userId;
@Column(name = "uuid")
@NotNull
private UUID uuid;
@Column(name = "phoneNumber")
@NotNull
private String phoneNumber;
@Column(name = "locationSource")
@NotNull
private String locationSource;
@Column(name = "dateTimeRequested")
private Timestamp dateTimeRequested;
@Column(name = "dateTimeRequestExpires")
private Timestamp dateTimeRequestExpires;
@Column(name = "dateTimeCompleted")
private Timestamp dateTimeCompleted;
@Column(name = "s3Bucket")
private String s3Bucket;
@Column(name = "s3Key")
private String  s3Key;
@Column(name = "s3Etag")
private String s3Etag;
@Column(name = "s3Sha256Hash")
private String s3Sha256Hash;
@Column(name = "isScheduledForCompletion")
@NotNull
private Integer isScheduledForCompletion;

public ConnectionRequest() 

public ConnectionRequest(Long id,
                         Long userId,
                         UUID uuid,
                         String phoneNumber,
                         String locationSource,
                         Timestamp dateTimeRequested,
                         Timestamp dateTimeRequestExpires,
                         Timestamp dateTimeCompleted,
                         String s3Bucket,
                         String s3Key,
                         String s3Etag,
                         String s3Sha256Hash,
                         Integer isScheduledForCompletion) 
    this.id = id;
    this.userId = userId;
    this.uuid = uuid;
    this.phoneNumber = phoneNumber;
    this.locationSource = locationSource;
    this.dateTimeRequested = dateTimeRequested;
    this.dateTimeRequestExpires = dateTimeRequestExpires;
    this.dateTimeCompleted = dateTimeCompleted;
    this.s3Bucket = s3Bucket;
    this.s3Key = s3Key;
    this.s3Etag = s3Etag;
    this.s3Sha256Hash = s3Sha256Hash;
    this.isScheduledForCompletion = isScheduledForCompletion;


public Long getId() 
    return id;


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


public Long getUserId() 
    return userId;


public void setUserId(Long userId) 
    this.userId = userId;


public UUID getUuid() 
    return uuid;


public void setUuid(UUID uuid) 
    this.uuid = uuid;


public String getPhoneNumber() 
    return phoneNumber;


public void setPhoneNumber(String phoneNumber) 
    this.phoneNumber = phoneNumber;


public String getLocationSource() 
    return locationSource;


public void setLocationSource(String locationSource) 
    this.locationSource = locationSource;


public Timestamp getDateTimeRequested() 
    return dateTimeRequested;


public void setDateTimeRequested(Timestamp dateTimeRequested) 
    this.dateTimeRequested = dateTimeRequested;


public Timestamp getDateTimeRequestExpires() 
    return dateTimeRequestExpires;


public void setDateTimeRequestExpires(Timestamp dateTimeRequestExpires) 
    this.dateTimeRequestExpires = dateTimeRequestExpires;


public Timestamp getDateTimeCompleted() 
    return dateTimeCompleted;


public void setDateTimeCompleted(Timestamp dateTimeCompleted) 
    this.dateTimeCompleted = dateTimeCompleted;


public String getS3Bucket() 
    return s3Bucket;


public void setS3Bucket(String s3Bucket) 
    this.s3Bucket = s3Bucket;


public String getS3Key() 
    return s3Key;


public void setS3Key(String s3Key) 
    this.s3Key = s3Key;


public String getS3Etag() 
    return s3Etag;


public void setS3Etag(String s3Etag) 
    this.s3Etag = s3Etag;


public String getS3Sha256Hash() 
    return s3Sha256Hash;


public void setS3Sha256Hash(String s3Sha256Hash) 
    this.s3Sha256Hash = s3Sha256Hash;


public Integer getIsScheduledForCompletion() 
    return isScheduledForCompletion;


public void setIsScheduledForCompletion(Integer isScheduledForCompletion) 
    this.isScheduledForCompletion = isScheduledForCompletion;

【问题讨论】:

什么是ConnectionRequest 对象? @code_mechanic 这是数据库的名称。我是 JPA 查询的新手。我假设我写错了? 你将哪个类映射到 connection_request 表? @MatheusCirillo 实体表(name = "connection_request") 公共类 ConnectionRequest 编辑问题并发布您的整个ConnectionRequest 课程。我认为问题是由于本机查询而发生的。所以,可以肯定的是,我必须看到ConnectionRequest 类。 . . 【参考方案1】:

由于您将本机查询映射到实体对象,由于所有这些注释和所有内容,hibernate 会发现这是一个实体对象,它正在检查该对象是否在 persistence context 缓存中.

因此,它没有找到它并创建一个,但随后它尝试将查询中的结果集映射到此实体对象,但在映射时它没有找到所有列来初始化实体(注意这里的列是预期的,但如果值为 null,它可能会起作用)。

但是,如果提供了所有列,它就可以映射到实体对象。

让我举个例子,假设我有这个Car 实体

@Entity
@Table(name = "car")
public class Car 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @NotBlank(message = "car name`s must be not empty")
    private String name;
    @Column(name = "production_year", nullable = false)
    private LocalDateTime productionYear;
    private boolean tested;
    @ManyToOne
    @JoinColumn(name = "brand_id")
    private Brand brand;

我的存储库方法是这样的

@Query(value = "select id, name, brand_id, production_year from car", nativeQuery = true)
    List<Car> findAllCars();

注意tested 不存在,所以hibernate 发出同样的错误

could not execute query [select id, name, brand_id, production_year from car]

java.sql.SQLException: Column 'tested' not found.
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.23.jar:8.0.23]

但如果我包含tested

 @Query(value = "select id, name, brand_id, production_year, tested from car", nativeQuery = true)
    List<Car> findAllCars();

Hibernate 会这样做

      : Unable to locate native-sql query plan in cache; generating (select id, name, brand_id, production_year, tested from car)
2021-04-09 00:54:02.143 TRACE 40352 --- [nio-8080-exec-2] o.h.loader.custom.sql.SQLCustomQuery     : Starting processing of sql query [select id, name, brand_id, production_year, tested from car]
2021-04-09 00:54:02.198 TRACE 40352 --- [nio-8080-exec-2] o.h.l.c.sql.SQLQueryReturnProcessor      : Mapping alias [alias1] to entity-suffix [0_]
2021-04-09 00:54:02.206 TRACE 40352 --- [nio-8080-exec-2] org.hibernate.internal.SessionImpl       : SQL query: select id, name, brand_id, production_year, tested from car
2021-04-09 00:54:02.223 DEBUG 40352 --- [nio-8080-exec-2] org.hibernate.SQL                        : select id, name, brand_id, production_year, tested from car
Hibernate: select id, name, brand_id, production_year, tested from car
2021-04-09 00:54:02.364 TRACE 40352 --- [nio-8080-exec-2] o.h.r.j.i.ResourceRegistryStandardImpl   : Registering statemen

如果你再往下看,它会给出这样的结果

 : Object not resolved in any cache: [com.example.***.model.Brand#1]
2021-04-09 00:54:02.559 TRACE 40352 --- [nio-8080-exec-2] o.h.p.entity.AbstractEntityPersister     : Fetching entity: [com.example.***.model.Brand#1]
2021-04-09 00:54:02.560 DEBUG 40352 --- [nio-8080-exec-2] org.hibernate.SQL                        : select brand0_.id as id1_0_0_, brand0_.name as name2_0_0_, brand0_.production_year as producti3_0_0_ from brand brand0_ where brand0_.id=?
Hibernate: select brand0_.id as id1_0_0_, brand0_.name as name2_0_0_, brand0_.production_year as producti3_0_0_ from brand brand0_ where brand0_.id=?
2021-04-09 00:54:02.562 TRACE 40352 --- [nio-8080-exec-2] o.h.r.j.i.ResourceRegistryStandardImpl   : Registering statement [HikariProxyPreparedStatement

在这种情况下它成功转换。

解决您的问题

因此,如果您想使用要返回的实体,则必须提供所有字段,否则您可以使用界面投影或question 建议的东西

【讨论】:

完美解释!非常感谢! 一般原生查询,我一直使用自定义DTO或者界面投影(字段较小),所以尽量避免原生查询实体转换。

以上是关于JPA 查询对不在查询中的列抛出“未找到”错误的主要内容,如果未能解决你的问题,请参考以下文章

未找到匹配项时 JPA 查询的返回值

在 jpa 本机查询中选择特定列并映射到 pojo

MySQL“不在”查询

如何选择一个查询中的列不在其他查询的列之间的记录?

JPA 中的传递列表命名本机查询

Grafana 选择查询抛出错误 - “找不到名为 time 或 time_sec 的列”