在Hibernate SQL查询中,如何转义字段名中的?字符?

3

这是一个SQL Server数据库,开发人员很多年前为布尔值的列名添加了一个?字符。许多系统都访问此数据库,因此对我来说更改此列名并不是一个真正的选择。

在原生的MS工具中,这是有效的:

SELECT * FROM MyDatabase.dbo.[My Table] WHERE [Active?]= true

同样的查询在Hibernate的session.createSQLQuery中失败,Hibernate试图将方括号内的?解释为参数并抛出错误。
我已经尝试过使用反引号[Active?\],以及使用/!进行转义 [Active/!?] 和相反的!/ [Active!/?],但都没有效果。
我也在许多stackoverflow和网络论坛上寻找其他建议,但我尝试的其他方法都没有起作用。
这是Hibernate的一个bug吗? 在我看来,方括号中的任何内容都不应该被解释为参数。
具体错误是查询异常。
> Expected positional parameter count: 1, actual parameters:[]
joachim-isaksson回答说:[Active\\?]是它,附带查询字符串。

“Active?”这个映射是什么样子的? - Joachim Isaksson
@JoachimIsaksson,不确定您所说的“mapping”的意思。这不是HQL映射。我确实有一个映射到表的类,我可能也需要修改它,但错误发生在我实际分配myObject = query.list()之前的代码中。 - Marc Johnson
2
啊,错过了createSQLQuery部分。我会猜测是[Active\\?](即应该传递一个反斜杠给Hibernate,但要加倍,否则Java会将其删除),但我目前没有测试的设置。 - Joachim Isaksson
@JoachimIsaksson,就是这样。我本来以为我尝试过了,但字符串中出现了错误。 - Marc Johnson
2个回答

5
为了复制这个用例,我在我的 high-performance-java-persistence GitHub 仓库中创建了 SQLServerEscapeQuestionCharacterTest。假设您有以下 JPA 实体:
@Entity(name = "Post")
@Table(name = "[post]")
public static class Post {

    @Id
    private Long id;

    private String title;

    @Column(name = "[active?]")
    private boolean active;

    public Long getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }
}

这与以下数据库表相关:

CREATE TABLE [post] (
    id bigint not null, 
    [active?] bit, 
    title varchar(255), 
    PRIMARY KEY (id)
)

如果您创建以下的Post实体:
Post post = new Post();
post.setId(1L);
post.setTitle("High-Performance Java Persistence");
post.setActive(true);

entityManager.persist(post);

Hibernate将执行正确的INSERT语句:
INSERT INTO [post] (
    [active?], 
    title, 
    id
) 
VALUES (
    true, 
    'High-Performance Java Persistence', 
    1
)

执行JPQL查询时:
List<Post> posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "where p.active = :active", Post.class)
.setParameter("active", true)
.getResultList();

assertEquals(1, posts.size());

Hibernate使用JPA的@Column注解中的name属性,该属性已经对列名进行了转义:
SELECT p.id AS id1_0_,
       p.[active?] AS active2_0_,
       p.title AS title3_0_
FROM [post] p
WHERE p.[active?] = true

对于原生 SQL 查询,您需要转义 ? 字符,如下所示:

List<String> posts = entityManager
.createNativeQuery(
    "select p.title " +
    "from [post] p " +
    "where p.[active\\?] = :active")
.setParameter("active", true)
.getResultList();

assertEquals(1, posts.size());

而且,它的表现非常出色。


-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接