首先考虑一下上下文-我正在实现一个API,其中请求包含客户端感兴趣的字段,基本上是直接选择的参数。因为如果不采用这种方式进行限制,则数据的整体大小会很大,因此在序列化和传输数据以及限制从数据库检索的数据量方面,这样做显然具有性能优势。因此,在进行数据库查询时,我试图传递那些选择。
我面临的问题是,在使用select执行查询时,Hibernate希望存在与select参数相对应的特定构造函数。例如,如果我指定仅对id
类中的model
(长整数)和BasicInfo
(字符串)列感兴趣,那么Hibternate会尝试查找并调用BasicInfo(int, String)
构造函数。我收到的错误消息表明了这一点:
org.hibernate.hql.internal.ast.QuerySyntaxException:无法找到类上的适当构造函数[my.package.BasicInfo]。预期参数是:long,java.lang.String [选择新my.package.BasicInfo(generatedAlias0.id,generateAlias0.model)来自my.package.BasicInfo作为generateAlias0]
这不是我的选择。客户可能希望在一个请求中以此顺序要求输入model
(字符串)和serial
(也是字符串),而另一位客户可能希望以相反的顺序要求相同的字段。因为我只能创建BasicInfo(String, String)
构造函数的一种组合,所以请求之一将以相反的方式检索数据。即使忽略了这一事实,我也必须为可能请求的所有可能的字段创建所有可能的构造函数置换,这与类中存在的字段数量一起使效率非常低下,即使不是不可能。
我正在寻找的是一种强制Hibernate使用默认类构造器的方法,即使指定了select查询参数并使用setter设置请求的字段也是如此。如果不是那样,那么也许是另一种方式,它使我在每个请求发出时都不会从数据库中检索完整的行数据(然后将其限制在应用程序代码中,然后发送回客户端)。
我还试图注册一个自定义的Hibernate拦截器,并像这样重写其instantiate
方法:
,并且Hibternate尝试直接使用特定参数来调用构造函数。public class CustomInterceptor extends EmptyInterceptor { @Override public Object instantiate(String entityName, EntityMode entityMode, Serializable id) { if(entityName.equals(BasicInfo.class.getName())) return new BasicInfo(); return null; } }
希望这会改变对象创建策略。在这种情况下,当我不指定select参数时,此方法将被正确调用。但是,当给出选择参数时,将完全调用not
下面是项目的相关部分:
代码设置选择参数(为清楚起见,删除了代码的无关部分:
CriteriaQuery<T> query = cb.createQuery(responseClass); Root<T> from = query.from(responseClass); // Handle select CriteriaQuery<T> select = null; if(request.getSelect() != null) { List<Selection<?>> selectionList = new ArrayList<Selection<?>>(); for(String s : request.getSelect()) { selectionList.add(from.get(s)); } select = query.multiselect(selectionList); } else { // select all fields select = query.select(from); } TypedQuery<T> typedQuery = em.createQuery(select); List<T> itemsList = typedQuery.getResultList();
和
applicaion.yml
:
spring:
datasource:
platform: h2
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
首先考虑一下上下文-我正在实现一个API,其中请求包含客户端感兴趣的字段,基本上是直接选择的参数。因为数据的整体大小相当...
我使用较旧的界面,只需使用List<Object[]>
即可将结果集设置为setProjection(myProjectionList)
。 Object[]
不是您想要的,但是将其转换为Map<String, Object>
是单线的,在转换为JSON之后,您可能会看到与未完成的对象相同的东西。