【问题标题】:Spring Boot JPA - EntityManager converting ID field to uppercaseSpring Boot JPA - EntityManager 将 ID 字段转换为大写
【发布时间】:2015-03-26 06:01:31
【问题描述】:

我正在构建一个 Spring Boot 应用程序,它会根据以下属性自动配置我的 JPA 数据源。

spring.datasource.url=jdbc:jtds:sqlserver://localhost;DatabaseName=testDB;useCursors=true
spring.datasource.username=testDBUser
spring.datasource.password=test123
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.datasource.maxActive=100
spring.datasource.minIdle=5
spring.datasource.removeAbandoned=true
spring.datasource.removeAbandonedTimeout=300
spring.datasource.defaultTransactionIsolation=REPEATABLE_READ
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.use_query_cache=true  

现在,我有一张如下表

TableA{
String id;
String prop1;
String prop2;
String prop3;
}

失败的测试用例如下。正如您在下面看到的,我只是想比较 EntityManager 与 Spring Data Repository 的结果。

测试失败,因为 EntityManager 返回的“id”值为“D97”(大写),而 Spring Data 存储库返回的值为“d97”。实际值为“d97”。

@Test
public void testIfSpringRepositoryWorks() {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();

    List<TableAEntity> result = entityManager.createQuery("FROM TableAEntity WHERE id='d97'" , TableAEntity.class).getResultList();

    if(result==null) {
        Assert.fail("Empty Result from EntityManager for id: d97 ");
    } else {
        TableAEntity fromEntityManager = result.get(0);
        TableAEntity fromSpringJPA = tableARepository.findOne("d97");

        if(!fromEntityManager.equals(fromSpringJPA)) {
            Assert.fail("TableAEntity is not same");
        }
    }


    entityManager.getTransaction().commit();
    entityManager.close();
}

我不确定 EntityManager 为何将我的 id 字段转换为大写。请帮助找出根本原因。

谢谢!

【问题讨论】:

  • 可以发一下TableAEntity的equals方法吗?在您的测试中,您在哪里断言 Id 不同?
  • 嗨,史蒂夫.. equals 方法是通过 lombok 项目的基本实现...使用 @EqualsAndHashCode 注释。
  • 默认 SQLServer 配置不区分大小写。因此,如果您的数据包含 id 为 'd97' 的行和 'D97' 的行,则将返回这两行。这就是许多人选择对 Id 列使用数字类型的原因之一。见stackoverflow.com/questions/1411161/…
  • 我同意!但是为什么 EntityManager 表现不同呢?我们现有的应用程序是基于 Hibernate 的 SessionFactory 实现构建的,它也可以按预期工作(返回 'd97' 的实际值)。我应该有什么配置吗?
  • 开玩笑,我们断言实体管理器查询的结果只有一行。

标签: hibernate jpa spring-data spring-boot spring-data-jpa


【解决方案1】:

我不确定这是否是一个问题或需要我创建解决方法的情况。但这就是正在发生的事情。

在上面的测试中,我对 Spring JPA 的查询是

tableARepository.findOne("d97");

相当于

entityManager.find(TableA.class,"d97");

当两者中的任何一个都被执行时,下面的代码部分会形成 Hibernate Row Reader 逻辑中的实体键 (org.hibernate.loader.plan.exec.process.internal.RowSetProcessorHelper)。

public static EntityKey getOptionalObjectKey(QueryParameters queryParameters, SessionImplementor session) {
    final Object optionalObject = queryParameters.getOptionalObject();
    final Serializable optionalId = queryParameters.getOptionalId();
    final String optionalEntityName = queryParameters.getOptionalEntityName();

    return INSTANCE.interpretEntityKey( session, optionalEntityName, optionalId, optionalObject );
}

不用说,您作为键传递的任何参数理想情况下都是返回对象的主键值(忽略数据库返回的值)。

现在,当我执行查询时

 List<TableAEntity> result = entityManager.createQuery("FROM TableAEntity WHERE id='d97'" , TableAEntity.class).getResultList()

由于我没有直接将任何主键传递给休眠它可能只是保留休眠返回的值。

现在由于 SQLServer 默认排序规则不区分大小写,它在返回数据时将我的主键大写。

我不确定 Hibernate 覆盖数据库返回的主键值的原因。

但是,如果 hibernate 具有关闭此类行处理逻辑的功能会很有帮助。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-25
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 2020-03-16
    • 2015-10-20
    • 1970-01-01
    • 2018-04-04
    相关资源
    最近更新 更多