任意の列とサブクエリを結合する複雑なクエリには、JPASQLQueries を使用する必要があります。そのようなクエリの 1 つは、DB から文字列を返し、これを列挙型に射影して DTO にする必要があります。このマッピングは、その特定の値に対して DTO でセッターを呼び出そうとすると、「不正な引数の型」で失敗します。
DTO と同じ構造を持つエンティティへのマッピングが機能します。
これは私が使用するクエリです:
final QOrderHeader orderHeader = QOrderHeader.orderHeader;
QOrderHeader orderGroup = new QOrderHeader("orderGroup");
QOrderPosition orderPosition = QOrderPosition.orderPosition;
SQLTemplates templates = new OracleTemplates();
JPASQLQuery orderQuery = new JPASQLQuery(em, templates);
Predicate preds = OrderHeaderPredicate.matchesSearchCriteria(searchCriteria);
// select from entity metadata, bind onto DTO, use entity metadata
List<OrderHeaderDTO> orderHeaderWithInfos = orderQuery //
.from(orderHeader) //
.list(Projections.bean(OrderHeaderDTO.class, //
.. some values left out
orderHeader.orderGroup, //
orderHeader.orderTypeCode, //
orderHeader.stateCode, //
orderHeader.stateReason, //
orderHeader.testNumber0,
orderHeader.testNumber1
)); //
DTO (stateCode dito) で orderTypeCode を設定しようとすると、クエリが失敗します。
これはエンティティです:
@Entity
@Table(name = "ORDERHEADER", uniqueConstraints = { @UniqueConstraint(columnNames = { "orderCode" }) })
public class OrderHeader extends BaseEntity {
protected String orderGroup; // no problem
protected OrderTypeCode orderTypeCode; // illegal argument type when calling setter
protected OrderHeaderState stateCode; // illegal argument type when calling setter
protected float testNumber0;
protected double testNumber1;
public OrderHeader() {
//DO NOT REMOVE. REQUIRED BY HIBERNATE.
}
public OrderHeader(OrderHeaderDTO dto) {
super(dto);
orderGroup = dto.getOrderGroup();
orderTypeCode = dto.getOrderTypeCode();
stateCode = dto.getStateCode();
testNumber0 = dto.getTestNumber0();
testNumber1 = dto.getTestNumber1();
}
@Override
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "HibSOrderheader")
@SequenceGenerator(name = "HibSOrderheader", sequenceName = "SOrderheader", allocationSize = 1)
public long getId() {
return id;
}
@Size(max = 30)
@Column(name = "ORDERGROUP", length = 30)
public String getOrderGroup() {
return orderGroup;
}
public void setOrderGroup(String orderGroup) {
this.orderGroup = orderGroup;
}
@Enumerated(EnumType.STRING)
@Column(name = "ORDERTYPECODE")
public OrderTypeCode getOrderTypeCode() {
return orderTypeCode;
}
public void setOrderTypeCode(OrderTypeCode orderTypeCode) {
this.orderTypeCode = orderTypeCode;
}
@Enumerated(EnumType.STRING)
@Column(name = "STATECODE", columnDefinition = "varchar2(20)")
public OrderHeaderState getStateCode() {
return stateCode;
}
protected void setStateCode(OrderHeaderState stateCode) {
this.stateCode = stateCode;
}
@Column(name = "TESTNUMBER0")
public float getTestNumber0() {
return testNumber0;
}
public void setTestNumber0(float testNumber0) {
this.testNumber0 = testNumber0;
}
@Column(name = "TESTNUMBER1")
public double getTestNumber1() {
return testNumber1;
}
public void setTestNumber1(double testNumber1) {
this.testNumber1 = testNumber1;
}
}
そして列挙型:
public enum OrderTypeCode {
NORMAL,
INVENTORY,
TRANSFER,
RELOCATE
}
そしてDTO:
public class OrderHeaderDTO extends BaseEntityDTO {
private String orderGroup;
private OrderTypeCode orderTypeCode;
private OrderHeaderState stateCode;
private float testNumber0;
private double testNumber1;
public OrderHeaderDTO() {
super();
}
@QueryProjection
public OrderHeaderDTO(IBaseEntity base, String orderCode,
String orderGroup, OrderTypeCode orderTypeCode, int hostId, int priority, String creationMode,
String shippingMode, String stagingArea, Date requestedDeliveryTime, String deliveryNote,
String deliveryCode, String customerCode, String customerOrderCode, String headerText,
OrderHeaderState stateCode, String stateReason, Date stateTime, List<OrderPositionDTO> orderPosition, float testNumber0,
double testNumber1) {
super(base);
this.orderGroup = orderGroup;
this.orderTypeCode = orderTypeCode;
this.stateCode = stateCode;
this.testNumber0 = testNumber0;
this.testNumber1 = testNumber1;
}
@QueryProjection
public OrderHeaderDTO(long id, long version, Date creationTime, Date lastUpdateTime,
String orderGroup, OrderTypeCode orderTypeCode, OrderHeaderState stateCode,
float testNumber0, double testNumber1) {
super(id, version, creationTime, lastUpdateTime);
this.orderGroup = orderGroup;
this.orderTypeCode = orderTypeCode;
this.stateCode = stateCode;
this.testNumber0 = testNumber0;
this.testNumber1 = testNumber1;
}
/**
* Copy constructor (shallow copy)
* @param arg Original value
*/
public OrderHeaderDTO(OrderHeaderDTO arg) {
super(arg);
orderGroup = arg.orderGroup;
orderTypeCode = arg.orderTypeCode;
creationTime = arg.creationTime;
stateCode = arg.stateCode;
testNumber0 = arg.testNumber0;
testNumber1 = arg.testNumber1;
}
public String getOrderGroup() {
return orderGroup;
}
@Enumerated(EnumType.STRING)
public OrderTypeCode getOrderTypeCode() {
return orderTypeCode;
}
public OrderHeaderState getStateCode() {
return stateCode;
}
public void setOrderGroup(String orderGroup) {
this.orderGroup = orderGroup;
}
public void setOrderTypeCode(OrderTypeCode orderTypeCode) {
this.orderTypeCode = orderTypeCode;
}
public void setStateCode(OrderHeaderState stateCode) {
this.stateCode = stateCode;
}
public float getTestNumber0() {
return testNumber0;
}
public void setTestNumber0(float testNumber0) {
this.testNumber0 = testNumber0;
}
public double getTestNumber1() {
return testNumber1;
}
public void setTestNumber1(double testNumber1) {
this.testNumber1 = testNumber1;
}
}
最後にスタック トレースがスローされます。
org.springframework.dao.InvalidDataAccessApiUsageException: argument type mismatch; nested exception is java.lang.IllegalArgumentException: argument type mismatch
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:296)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:107)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy55.searchOrderWithInfoForCriteria(Unknown Source)
at com.stoecklin.wms.dbunittest.implementation.repository.OrderHeaderCustomRepoIT.test_noCriteria(OrderHeaderCustomRepoIT.java:188)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.mysema.util.BeanMap.put(BeanMap.java:330)
at com.mysema.util.BeanMap.put(BeanMap.java:51)
at com.mysema.query.types.QBean.newInstance(QBean.java:250)
at com.mysema.query.support.NumberConversions.newInstance(NumberConversions.java:65)
at com.mysema.query.jpa.FactoryExpressionTransformer.transformTuple(FactoryExpressionTransformer.java:50)
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:95)
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:431)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2342)
at org.hibernate.loader.Loader.list(Loader.java:2337)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1827)
at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:231)
at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:157)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:268)
at com.mysema.query.jpa.sql.AbstractJPASQLQuery.getResultList(AbstractJPASQLQuery.java:193)
at com.mysema.query.jpa.sql.AbstractJPASQLQuery.list(AbstractJPASQLQuery.java:224)
at com.stoecklin.wms.repository.implementation.OrderHeaderRepositoryImpl.searchJPASQLIntoDTO(OrderHeaderRepositoryImpl.java:347)
at com.stoecklin.wms.repository.implementation.OrderHeaderRepositoryImpl.searchOrderWithInfoForCriteria(OrderHeaderRepositoryImpl.java:517)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:344)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
... 37 more
質問は次のとおりです。
- プロジェクションで一部の列、つまり列挙型に型変換式を提供するにはどうすればよいでしょうか?
- 生成されたエンティティ メタデータ (apt-maven-plugin から) を JPASQL に使用することは可能ですか?
どんな助けでも大歓迎です。
また、他のさまざまなバリアントも調べましたが、それほど良い結果は得られませんでした。
- プロジェクションに (querydsl-maven-plugin からの) ネイティブ SQL メタデータを使用してもあまり変化はありませんでしたが、追加の型マッピングの問題が明らかになりました。
- ネイティブ SQL メタデータからの選択も同じ動作でした。
- エンティティへの射影は機能しますが、DTO に (合成された値も) 直接入力する必要があるため、これは意図したものではありません。エンティティを使用する場合は、後でエンティティを DTO にコピーする必要があります。
編集:使用されるバージョン:
QueryDSL: 3.2.4
Spring: 3.2.2.RELEASE
Hibernate:4.2.6.Final
使用する最後のクエリは次のようになります (SQL のみ)。
SELECT
oh.*,
(select count(id) -- correlated subquery
from orderposition p
where p.orderHeaderID = oh.id) as nofPosPerOrder,
og.mostImportantPrioInGroup,
og.earliestDeliveryTime,
og.earliestCreationTime
FROM orderHeader oh LEFT JOIN -- left join with aggregating query for order group
(SELECT g.orderGroup,
min(g.priority) as mostImportantPrioInGroup,
min(g.requestedDeliveryTime as earliestDeliveryTime,
min(g.requestedCreationTime as earliestCreationTime
FROM orderHeader g
GROUP by g.orderGroup) og
ON oh.orderGroup = og.orderGroup
WHERE ?????
ORDER BY .