Java 如何解决类型转换错误(运算符不存在:bigint=bytea)?

Java 如何解决类型转换错误(运算符不存在:bigint=bytea)?,java,postgresql,spring-data-jpa,Java,Postgresql,Spring Data Jpa,我正在尝试将一个在Microsoft SQL Server上运行良好的Spring启动应用程序迁移到PostgreSQL。但是,在清理查询以匹配PGSQL语法后,我得到一个错误,该错误表示: org.postgresql.util.PSQLException: ERROR: operator does not exist: bytea = integer Hint: No operator matches the given name and argument type(s). You mi

我正在尝试将一个在Microsoft SQL Server上运行良好的Spring启动应用程序迁移到PostgreSQL。但是,在清理查询以匹配PGSQL语法后,我得到一个错误,该错误表示:

org.postgresql.util.PSQLException: ERROR: operator does not exist: bytea = integer
  Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
  Position: 868
问题是,我有40多个控制器,并使用相同的模式对它们进行编码,它们在SQL Server上运行良好,但在迁移到PostgreSQL时,40个控制器中有3个抛出了这个有趣的错误。我将请求作为
Long
传递给控制器,数据库中的列也是
Long
bigint
)。所以我不知道这是从哪里来的。我在谷歌上搜索了很多次,但没有解决问题。这里有一些我查过的有价值的链接

  • 。。。还有更多
以下是其中一个控制器:

    @PostMapping("/date-sum")
    public ResponseEntity<Object> sumRecordsWithDate(@RequestBody SearcherDto searcherDto) {

        Long type = searcherDto.getCompanyTypeId();
        Long process = searcherDto.getProcessTypeFk();
        Long process1 = searcherDto.getProcessTypeFk1();
        Long process2 = searcherDto.getProcessTypeFk2();
        Long process3 = searcherDto.getProcessTypeFk3();
        LocalDateTime start = LocalDateTime.of(LocalDate.from(searcherDto.getStartDate()), LocalTime.of(0, 0, 0));
        LocalDateTime end = LocalDateTime.of(LocalDate.from(searcherDto.getEndDate()), LocalTime.of(23, 59, 59));


        SumInterface sumInterface = sumRepository
                .sumWithDate(process, process1, process2,
                        process3, type, start, end);

        return ResponseEntity.ok(new JsonResponse("See Data Object for Details", sumInterface));
    }
下面是我的本机查询存储库:

@Query(value=“选择sum(case when(IS_Query=false,SUBMITTED=true),然后b.AMOUNT else null end)作为挂起,”+
未提交的金额(当(提交=false或提交为NULL时的大小写)则为b.AMOUNT else NULL end+
sum(case when((SUBMITTED=true))然后1 else null end)作为已提交+
合计(b.金额)作为总申请+
查询的总和(当(IS_queryed=true)和b.AMOUNT else null end时的大小写)+
已批准的金额(如果为(批准=真),则为b.金额,否则为空结束)+
“未批准的金额(批准时为小写=false),然后b.金额否则为空”+
“来自年度报告a”+
“在a.id=b.RECORD\u id和b.PROCESS\u TYPE\u FK=a.PROCESS\u TYPE\u FK上左连接付款\u历史记录b”+
“在c.id=a.COMPANY\u FK上左键加入公司c”+

“WHERE(a.FINANCIAL\u YEAR\u END>=:startDate和a.FINANCIAL\u YEAR\u END最有可能是
LocalDateTime
。您的驱动程序不知道如何处理它,可能正在使用默认的Java序列化将其转换为
bytea
(与
bigint
相比)

最简单的解决方案(因为您已经在使用本机查询而不是JPA)是自己进行转换。只有您知道应该如何进行转换(epochtime?秒或毫秒?什么时区?),但类似于:

long startValue=start.atOffset(ZoneOffset.UTC).toepochssecond();
更高级的配置将涉及注册正确的转换器。同样,不会有现成的转换器,因为没有定义的方法从本地日期时间获取整数


我建议您改用完全指定的类型(
OffsetDateTime
ZonedDateTime
Instant
),并在您的模式中使用适当的日期时间类型。

对此有一个解决方法,但它不会有实际的修复,除非PostgreSQL团队决定在其解析器中创建延迟类型检查,以便在初始go时传递null

因此,解决方法是

private static final Long LONG_CONST = 0L;
@PostMapping("/date-sum")
public ResponseEntity<Object> sumRecordsWithDate(@RequestBody SearcherDto searcherDto) {

    Long type = searcherDto.getCompanyTypeId();
    Long process = searcherDto.getProcessTypeFk();
    Long process1 = searcherDto.getProcessTypeFk1();
    Long process2 = searcherDto.getProcessTypeFk2();
    Long process3 = searcherDto.getProcessTypeFk3();
    LocalDateTime start = LocalDateTime.of(LocalDate.from(searcherDto.getStartDate()), LocalTime.of(0, 0, 0));
    LocalDateTime end = LocalDateTime.of(LocalDate.from(searcherDto.getEndDate()), LocalTime.of(23, 59, 59));

    // difference starts here
    EntityManager em = getEntityManager();

    Query q = em.createNativeQuery(..., ReturnType.class);
    // or createNamedQuery if you've registered it via NamedNativeQuery, which I recommend
    q.setParameter("processTypeFk", LONG_CONST).setParameter("processTypeFk", process);
    q.setParameter("processTypeFk1", LONG_CONST).setParameter("processTypeFk1", process1);
    q.setParameter("processTypeFk2", LONG_CONST).setParameter("processTypeFk2", process2);
    q.setParameter("processTypeFk3", LONG_CONST).setParameter("processTypeFk3", process3);
    q.setParameter("companyTypeId", LONG_CONST).setParameter("companyTypeId", companyTypeId)
    // these are never null, so we don't need to type-set them.
    q.setParameter("startDate", start);
    q.setParameter("endDate", end);

    ... q.getResultList();

    return ResponseEntity.ok(new JsonResponse("See Data Object for Details", sumInterface));
}
private static final Long_CONST=0L;
@邮戳(“/日期和”)
公共响应性sumRecordsWithDate(@RequestBody SearcherTo SearcherTo){
Long type=searcherDto.getCompanyTypeId();
Long process=searcherDto.getProcessTypeFk();
Long process1=searcherDto.getProcessTypeFk1();
Long process2=searcherDto.getProcessTypeFk2();
Long process3=searcherDto.getProcessTypeFk3();
LocalDateTime start=LocalDateTime.of(LocalDate.from(searcherDto.getStartDate()),LocalTime.of(0,0,0));
LocalDateTime end=LocalDateTime.of(LocalDate.from(searcherDto.getEndDate()),LocalTime.of(23,59,59));
//区别从这里开始
EntityManager em=getEntityManager();
Query q=em.createNativeQuery(…,ReturnType.class);
//或者createNamedQuery,如果您已经通过NamedNativeQuery注册了它,我建议您这样做
q、 setParameter(“processTypeFk”,LONG_CONST)。setParameter(“processTypeFk”,process);
q、 setParameter(“processTypeFk1”,LONG_CONST).setParameter(“processTypeFk1”,process1);
q、 setParameter(“processTypeFk2”,LONG_CONST).setParameter(“processTypeFk2”,process2);
q、 setParameter(“processTypeFk3”,LONG_CONST).setParameter(“processTypeFk3”,process3);
q、 setParameter(“companyTypeId”,LONG_CONST)。setParameter(“companyTypeId”,companyTypeId)
//它们永远不会为null,因此我们不需要对它们进行类型设置。
q、 设置参数(“开始日期”,开始);
q、 设置参数(“结束日期”,结束);
…q.getResultList();
返回ResponseEntity.ok(新的JsonResponse(“参见数据对象了解详细信息”,sumInterface));
}

这里发生的事情是,第一次调用
setParameter
时,您使用一个非空值来确保Hibernate正确地确定该参数的类型,然后第二次调用时,您设置了正确的(可能为空)值,但类型检查已完成,因此跳过了该检查。

经过几天的头脑风暴后,我能够修复该问题。我发现PostgreSQL驱动程序无法处理参数中的所有抽象。它将一些抽象视为空。因此,在尝试了不同的建议后,我所做的是重新设计了参数编写代码并创建新端点以处理其他抽象级别

简单地说,我减少了repository和controller方法的重载,以避免传递null,因为MS-SQL可以处理这个问题,但是postgreSQL不能处理它

以下是我的新存储库接口方法:

    @Query(value = "SELECT count(case when (IS_QUERIED = false AND SUBMITTED = true) 
then 1 else null end) AS pending, 
count(case when (SUBMITTED = false OR SUBMITTED IS NULL) then 1 else null end) AS notSubmitted, 
count(case when ( (SUBMITTED = true)) then 1 else null end) AS submitted, count(*) AS totalApplications, 
count(case when (IS_QUERIED = true) then 1 else null end) AS queried, 
count(case when (APPROVED = true) then 1 else null end) AS approved, 
count(case when (APPROVED = false) then 1 else null end) AS notApproved 
FROM ANNUAL_RETURNS a LEFT JOIN PAYMENT_HISTORY b ON a.id=b.RECORD_ID 
AND b.PROCESS_TYPE_FK = a.PROCESS_TYPE_FK LEFT JOIN COMPANY c 
ON c.id= a.COMPANY_FK WHERE (c.COMPANY_TYPE_FK=:companyTypeId OR :companyTypeId=0) 
AND a.PROCESS_TYPE_FK =:processTypeFk ", nativeQuery = true)
AnnualReturnInterface countReturn(@Param("processTypeFk") Long processTypeFk,
@Param("companyTypeId") Long companyTypeId);

以下是新的控制器方法:

@PostMapping("/count")
    public ResponseEntity<Object> countAnnualReturnRecordsByOneProcessType
(@RequestBody SearcherDto searcherDto) {

        Long companyType = searcherDto.getCompanyTypeId();
        Long processType = searcherDto.getProcessTypeFk();

        AnnualReturnInterface annualReturnInterface = annualReturnRepository
                .countAnnualReturnByOneProcessTypeAndCompanyType(processType, companyType);

        return ResponseEntity.ok(new JsonResponse("See Data Object for Details", annualReturnInterface));
    }

第二控制器如下:

@PostMapping("/count-all")
    public ResponseEntity<Object> countAnnualReturnRecordsByAllProcessType
(@RequestBody SearcherDto searcherDto) {

        Long companyType = searcherDto.getCompanyTypeId();
        AnnualReturnInterface annualReturnInterface = annualReturnRepository
                .countAnnualReturnByAllProcessTypeAndOrCompanyType(companyType);

        return ResponseEntity.ok(new JsonResponse("See Data Object for Details", annualReturnInterface));
    }

@PostMapping(“/count all”)
公共响应国家年度返回记录YallProcessType
(@RequestBody SearcherDto SearcherDto){
Long companyType=searcherDto.getCompanyTypeId();
AnnualReturnInterface AnnualReturnInterface=annualReturnRepository
.countAnnualReturnByAllProcessT
    @Query(value = "SELECT count(case when (IS_QUERIED = false AND SUBMITTED = true) 
then 1 else null end) AS pending, 
count(case when (SUBMITTED = false OR SUBMITTED IS NULL) then 1 else null end) AS notSubmitted, 
count(case when ( (SUBMITTED = true)) then 1 else null end) AS submitted, count(*) AS totalApplications, 
count(case when (IS_QUERIED = true) then 1 else null end) AS queried, 
count(case when (APPROVED = true) then 1 else null end) AS approved, 
count(case when (APPROVED = false) then 1 else null end) AS notApproved 
FROM ANNUAL_RETURNS a LEFT JOIN PAYMENT_HISTORY b ON a.id=b.RECORD_ID 
AND b.PROCESS_TYPE_FK = a.PROCESS_TYPE_FK LEFT JOIN COMPANY c 
ON c.id= a.COMPANY_FK WHERE (c.COMPANY_TYPE_FK=:companyTypeId OR :companyTypeId=0) 
AND a.PROCESS_TYPE_FK =:processTypeFk ", nativeQuery = true)
AnnualReturnInterface countReturn(@Param("processTypeFk") Long processTypeFk,
@Param("companyTypeId") Long companyTypeId);

@PostMapping("/count")
    public ResponseEntity<Object> countAnnualReturnRecordsByOneProcessType
(@RequestBody SearcherDto searcherDto) {

        Long companyType = searcherDto.getCompanyTypeId();
        Long processType = searcherDto.getProcessTypeFk();

        AnnualReturnInterface annualReturnInterface = annualReturnRepository
                .countAnnualReturnByOneProcessTypeAndCompanyType(processType, companyType);

        return ResponseEntity.ok(new JsonResponse("See Data Object for Details", annualReturnInterface));
    }

    @Query(value = "SELECT count(case when (IS_QUERIED = false AND SUBMITTED = true) 
then 1 else null end) AS pending, count(case when (SUBMITTED = false OR SUBMITTED IS NULL)
 then 1 else null end) AS notSubmitted, count(case when ( (SUBMITTED = true)) then 1 
else null end) AS submitted, count(*) AS totalApplications, 
count(case when (IS_QUERIED = true) then 1 else null end) AS queried, 
count(case when (APPROVED = true) then 1 else null end) AS approved, 
count(case when (APPROVED = false) then 1 else null end) AS notApproved  
FROM ANNUAL_RETURNS a LEFT JOIN PAYMENT_HISTORY b ON a.id=b.RECORD_ID 
AND b.PROCESS_TYPE_FK = a.PROCESS_TYPE_FK LEFT JOIN COMPANY c ON 
c.id= a.COMPANY_FK WHERE (c.COMPANY_TYPE_FK=:companyTypeId OR :companyTypeId=0) AND a.PROCESS_TYPE_FK in (9542,9594,9598) ", nativeQuery = true)

    AnnualReturnInterface countAnnualReturnByAllProcessTypeAndOrCompanyType(@Param("companyTypeId") Long companyTypeId);
    }

@PostMapping("/count-all")
    public ResponseEntity<Object> countAnnualReturnRecordsByAllProcessType
(@RequestBody SearcherDto searcherDto) {

        Long companyType = searcherDto.getCompanyTypeId();
        AnnualReturnInterface annualReturnInterface = annualReturnRepository
                .countAnnualReturnByAllProcessTypeAndOrCompanyType(companyType);

        return ResponseEntity.ok(new JsonResponse("See Data Object for Details", annualReturnInterface));
    }