【问题标题】:JPQL IN clause with @Convert带有@Convert 的 JPQL IN 子句
【发布时间】:2021-01-11 15:06:03
【问题描述】:

在非规范化 PostgreSQL 数据库中:“Document”和“Record”两个表

Document 有一个 id 和一个逗号分隔的列 recodeIds

--------------------------------------
| id (VARCHAR) | recordIds (VARCHAR) |
--------------------------------------
| 1            | 3,1                 |
| 2            | 2                   |
--------------------------------------

记录有id和名字

---------------------------------
| id (VARCHAR) | name (VARCHAR) |
---------------------------------
| 1            | X              |
| 2            | Y              |
| 3            | Z              |
---------------------------------

DocumentModel 与 @Convert

@Entity
@Table(name = "Document")
public class DocumentModel {
    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "recodeIds")
    @Convert(converter = RecordsConverter.class)
    private Set<String> records;
}

RecordsConverter

public class RecordsConverter implements AttributeConverter<Set<String>, String> {
    @Override
    public String convertToDatabaseColumn(Set<String> recordTypes) {
        return String.join(",", recordTypes);
    }
    @Override
    public Set<String> convertToEntityAttribute(String recordTypes) {
        return Arrays.stream(recordTypes.split(",")).collect(Collectors.toSet());
    }
}

JPQL现在我正在尝试在@Query 中使用记录

@Query("SELECT D.id, R.name)"
    + " FROM DocumentModel D"
    + " JOIN RecordModel R"
    + " ON R.id IN D.records"
    + " WHERE D.id = :docId"

这仅适用于 recordIds 具有单一值(例如:docId = 2)

如果 recordIds 有多个值(例如:docId = 1),即使:

  • 嵌套 SELECT 不起作用
  • 带和不带 () 的 IN 子句不起作用
  • MEMBER OF 子句不起作用
  • 导致本机 SQL 直接不起作用
  • @Formula 不起作用

问题似乎在于记录应该是单引号逗号分隔,而不仅仅是逗号分隔,因为它们是字符串。 (本机 SQL 查询在这种情况下有效)

问:如何在不更改 RecordsConverter 并且希望不使用 JPA 规范的情况下使用 JPQL(非本地查询)来完成这项工作?

【问题讨论】:

  • 解决这个问题的最好方法是规范化你的数据模型。将逗号分隔的值存储在单个列中是一个巨大的错误
  • 你是对的,但客户拒绝了:/
  • @AhmedGhoneim 它是否适用于您的 JPQL 的 sql 查询模拟?
  • 没有。它仅适用于单引号逗号分隔值
  • 您可以创建一个显示document 表的规范化版本的视图。然后您使用常规连接将其与Record 表结合起来

标签: postgresql hibernate spring-data-jpa jpql


【解决方案1】:

好像我受到了Hibernate bug的影响

作为一种解决方法,使用集合包装器:

@Data
@Builder
public class MyCollection implements Serializable {
    private final Set<String> collection;
}

并更改您的属性转换器:

public class MyConverter implements AttributeConverter<MyCollection, String> {
    @Override
    public String convertToDatabaseColumn(MyCollection myCollection) {
        return String.join(",", myCollection.getCollection());
    }
    @Override
    public MyCollection convertToEntityAttribute(String myCollection) {
        return MyCollection.builder()
                .collection(Arrays.stream(myCollection.split(",")).collect(Collectors.toSet()))
                .build();
    }
}

还有你的模特:

@Entity
@Table(name = "MY_MODEL")
public class MyModel {
    @Column(name = "MY_COLLECTION")
    @Convert(converter = MyConverter.class)
    private MyCollection myCollection;
}

这对我有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    • 2015-07-05
    • 2018-06-08
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多