简体   繁体   English

如何 HQL 查询没有 ID 的项目?

[英]How to HQL query an item with no Id?

I'm in a situation where I had a LOT of data in my DB, and I decided to move to Hibernate.我的数据库中有很多数据,我决定转移到 Hibernate。 One of my tables (let's call it "MyItem") didn't have any suitable Id.我的一张表(我们称之为“MyItem”)没有任何合适的 ID。 It contained only one column, 'json'.它只包含一列“json”。

For some reason (related to the quantity of data), I could not migrate all the MyItem data so they all have a new unique identifier.由于某种原因(与数据量有关),我无法迁移所有 MyItem 数据,因此它们都有一个新的唯一标识符。

What I did was to add a new 'identifier' column to this table (so two columns: 'json' and 'identifier'), and in my Java code I declared my entity so that it looks like this:我所做的是在此表中添加一个新的“标识符”列(因此有两列:“json”和“标识符”),并在我的 Java 代码中声明了我的实体,使其看起来像这样:

@Entity
@Table
public class MyItem {
    @Lob
    private String json;

    private String identifier;

    public MyItem() {
    }

    public MyItem(String json) {
        this.json = json;
    }

    public void setIdentifier(String id) {
        //fake
    }

    @Id
    public String getIdentifier() {
        if (identifier == null) {
            identifier = UUID.randomUUID().toString();
        }
        return identifier;
    }
    
    public String getJson() {
        return json;
    }
    
    public void setJson(String json) {
        this.json = json;
    }
}

I can create and access my new data correctly (new ones are generated with an Id), but I am struggling accessing the oldest one (those having null in their identifier column) only when I do it through HQL.我可以正确地创建和访问我的新数据(新数据是使用 Id 生成的),但是只有当我通过 HQL 进行访问时,我才很难访问最旧的数据(那些在其标识符列中包含 null 的数据)。

Here is the way I perform my query (of course, I have changed some stuffs for the question, please disregard my fake ""json"", of course it's not json, it's just for the example):这是我执行查询的方式(当然,我已经为问题更改了一些东西,请忽略我的假“json”,当然不是json,这只是为了示例):

String myJson = "6044c44a-dd17-40ca-b66b-cb9d29cf8a33-1-0-1";
Query<MyItem> query = statelessSession.createQuery("FROM MyItem WHERE json = :json", MyItem.class);
query.setParameter("json", myJson);
query.setFetchSize(FETCH_SIZE);
query.setReadOnly(true);
query.setLockMode("a", LockMode.NONE);
try (ScrollableResults MyItemList = query.scroll(ScrollMode.FORWARD_ONLY)) {
    while (MyItemList.next()) {
        MyItem myItem = (MyItem) MyItemList.get(0);
        myItem.getJson());
    }
}

And I get a NPE on the myItem.getJson();我在 myItem.getJson(); 上得到一个 NPE;

Here are Hibernate traces:以下是 Hibernate 迹线:

14:55:58.263 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.query.spi.QueryPlanCache@157 - Located HQL query plan in cache (FROM MyItem WHERE json = :json) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.query.spi.QueryPlanCache@157 - Located HQL query plan in cache (FROM MyItem WHERE json = :json) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.query.spi.HQLQueryPlan@344 - Iterate: FROM MyItem WHERE json = :json 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] TRACE o.h.r.j.i.AbstractLogicalConnectionImplementor@66 - Preparing to begin transaction via JDBC Connection.setAutoCommit(false) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.spi.QueryParameters@325 - Named parameters: {json=6044c44a-dd17-40ca-b66b-cb9d29cf8a33-1-0-1} 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] TRACE o.h.r.j.i.AbstractLogicalConnectionImplementor@68 - Transaction begun via JDBC Connection.setAutoCommit(false) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] TRACE o.h.r.t.b.j.i.JdbcResourceLocalTransactionCoordinatorImpl@172 - ResourceLocalTransactionCoordinatorImpl#afterBeginCallback 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] DEBUG o.h.e.t.internal.TransactionImpl@56 - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] DEBUG org.hibernate.SQL@94 - 
 select 
 myit0_.identifier as identifi1_0_,
 myit0_.json as json5_0_
 from 
 MyItem myit0_ 
 where 
 myit0_.json=? 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] DEBUG o.h.e.t.internal.TransactionImpl@78 - begin 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] DEBUG o.s.j.d.DriverManagerDataSource@144 - Creating new JDBC DriverManager Connection to [jdbc:com.db://localhost:1234/mydb] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.r.j.i.ResourceRegistryStandardImpl@68 - Registering statement [[Statement - handle 1 (Connection ID - 25769822844)]] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.e.j.internal.JdbcCoordinatorImpl@339 - Registering last query statement [[Statement - handle 1 (Connection ID - 25769822844)]] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.type.descriptor.sql.BasicBinder@65 - binding parameter [1] as [VARCHAR] - [6044c44a-dd17-40ca-b66b-cb9d29cf8a33-1-0-1] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE org.hibernate.loader.Loader@2034 - Bound [2] parameters total 
14:55:58.266 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.r.j.i.ResourceRegistryStandardImpl@196 - Registering result set [com.db.ResultSet@55612811] 
14:55:58.266 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.t.descriptor.sql.BasicExtractor@51 - extracted value ([identifi1_0_] : [VARCHAR]) - [null] 
14:55:58.266 [TileBuilderCallable_pool-11-thread-2] DEBUG org.hibernate.loader.Loader@1532 - Result row: null 
14:55:58.267 [TileBuilderCallable_pool-11-thread-2] TRACE org.hibernate.loader.Loader@1149 - Total objects hydrated: 0

The only idea I have here is to try/catch the NPE so I migrate the data on the fly by adding an identifier.我在这里唯一的想法是尝试/捕获 NPE,因此我通过添加标识符来动态迁移数据。 Is there any other smarter way to perform my query?还有其他更聪明的方法来执行我的查询吗?

Thanks: :)谢谢: :)

  1. This looks suspicious:这看起来很可疑:
public void setIdentifier(String id) {
  //fake
}

Why you do not set the identifier field here?为什么不在这里设置identifier字段? Try to correct it to this:尝试将其更正为:

public void setIdentifier(String id) {
  this.identifier = id;
}

and recheck your problem.并重新检查您的问题。

  1. You are trying to mix up access strategies what can lead to problems.您正在尝试混合可能导致问题的访问策略 By default, the placement of the @Id annotation gives the default access strategy.默认情况下, @Id注释的位置提供了默认访问策略。 When placed on a field, Hibernate will assume field-based access.放置在字段上时,Hibernate 将采用基于字段的访问。 When placed on the identifier getter, Hibernate will use property-based access.当放置在标识符 getter 上时,Hibernate 将使用基于属性的访问。 So, hibernate will ignore your @Lob annotation, as you use property-based access.因此,当您使用基于属性的访问时,hibernate 将忽略您的@Lob注释。

  2. Your implementation of the getIdentifier method also looks suspicious.您对getIdentifier方法的实现看起来也很可疑。 I would suggest you to use @GeneratedValue for the entity id generation.我建议您使用@GeneratedValue生成实体 ID。 Hibernate supports UUID identifier value generation . Hibernate 支持UUID 标识符值生成

So, I would suggest you to correct your mapping in this way:因此,我建议您以这种方式更正您的映射:

import org.hibernate.annotations.Type;

@Entity
@Table
public class MyItem {

  @Id
  @GeneratedValue
  @Type(type = "uuid-char")
  private UUID identifier;
  
  @Lob
  private String json;

  // ...

  @Transient
  public String getIdentifierAsString() {
     return identifier != null ? identifier.toString() : null;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM