我使用带有JPA 2.1的java EE7,我尝试进行如下查询:
select generatedAlias0, count(generatedAlias1), count(generatedAlias2)
from Accounts as generatedAlias0
left join items as generatedAlias1
on ( generatedAlias1.creator_id=generatedAlias0.id ) and ( generatedAlias1.status='CLOSED' )
left join items as generatedAlias2
on ( generatedAlias2.creator_id=generatedAlias0.id ) and ( generatedAlias2.status='OPEN' )
where 1=1 group by generatedAlias0.id.
我有以下实体:
@Entity
@Table( name = "accounts" )
public class Account
{
@Id
@GeneratedValue( generator = "acct_seq" )
@SequenceGenerator( name = "acct_seq", sequenceName = "accounts_id_seq", allocationSize = 1 )
private Long id;
@OneToMany( fetch = FetchType.LAZY )
@OrderBy( "id desc" )
@JoinTable( name = "items", joinColumns = @JoinColumn( name = "creator_id", referencedColumnName = "id" ), inverseJoinColumns = @JoinColumn( name = "id", referencedColumnName = "id" ) )
private List<Item> items;
...
}
以下方法创建查询:
public List<AccountDTO> findAccounts( int first, int pageSize, String sortField, String sortOrder,
Map<String, Object> filters )
{
CriteriaBuilder builder = em.getCriteriaBuilder( );
CriteriaQuery<Tuple> criteriaQuery = builder.createTupleQuery( );
Root<Account> root = criteriaQuery.from( Account.class );
Join<Account, Item> itemsPlaced = root.join( "items", JoinType.LEFT );
Join<Account, Item> itemsSold = root.join( "items", JoinType.LEFT );
List<Predicate> itemsPlacedConditions = new ArrayList<>( );
itemsPlacedConditions.add( builder.equal( itemsPlaced.get( "creator" ).get( "id" ), root.get( "id" ) ) );
itemsPlacedConditions.add( builder.equal( itemsPlaced.get( "status" ), "OPEN" ) );
itemsPlaced.on( itemsPlacedConditions.toArray( new Predicate[] {} ) );
List<Predicate> itemsSoldConditions = new ArrayList<>( );
itemsSoldConditions.add( builder.equal( itemsSold.get( "owner" ), root ) );
itemsSoldConditions.add( builder.equal( itemsSold.get( "status" ), "CLOSED" ) );
itemsSold.on( itemsSoldConditions.toArray( new Predicate[] {} ) );
Expression<Long> countPlaced = builder.count( itemsPlaced );
Expression<Long> countSold = builder.count( itemsSold );
criteriaQuery
.select( builder.tuple( root, countPlaced.alias( "itemsPlaced" ), countSold.alias( "itemsSold" ) ) );
if ( filters.containsKey( "fullName" ) )
{
criteriaQuery.where( getOrPredicate( filters, builder, root ) );
}
criteriaQuery.where( getAndPredicate( filters, builder, root, itemsPlaced ) );
List<Order> orderList = new ArrayList<>( );
if ( sortField != null )
{
orderList.add( sortOrder.equals( ASCENDING.value( ) ) ? builder.asc( root.get( sortField ) )
: builder.desc( root.get( sortField ) ) );
} else
{
orderList.add( builder.asc( root.get( "id" ) ) );
}
orderList.add( builder.desc( countPlaced ) );
criteriaQuery.groupBy( root.get( "id" ) );
List<Tuple> result = em.createQuery( criteriaQuery ).setFirstResult( first ).setMaxResults( pageSize )
.getResultList( );
List<AccountDTO> accts = new ArrayList<>( );
for ( Tuple tuple : result )
{
AccountDTO res = new AccountDTO( );
try
{
res = ReflectionUtil.copy( AccountDTO.class, tuple.get( 0 ) );
} catch (Exception e)
{
e.printStackTrace( );
}
res.setItemsPlaced( (Long) tuple.get( 1 ) );
res.setItemsSold( (Long) tuple.get( 2 ) );
accts.add( res );
}
return accts;
}
但是当我执行该方法时,我得到以下异常:
javax.servlet.ServletException:org.hibernate.hql.internal.ast.QuerySyntaxException:with-clause引用了两个不同的from子句元素[select generateAlias0,count(generatedAlias1),count(generatedAlias2)from com.persistence.entities .Account as generatedAlias0 left joinAlias0.items as generatedAlias1 with((1 = 1)and(generatedAlias1.status =:param0))and(generatedAlias1.creator.id = generatedAlias0.id)left join generatedAlias0.items as generatedAlias2 with(1 = 1)和(generatedAlias1.status =:param1)其中1 = 1 group by generatedAlias0.id]
我不明白为什么join.on方法不起作用以及keywith'with'出现的地方。我也尝试了很多例子,也许我的配置错了?
我的persistence.xml:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="persistence" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/postgresDS</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="openjpa.TransactionMode" value="managed" />
<property name="openjpa.ConnectionFactoryMode" value="managed" />
<property name="openjpa.jdbc.DBDictionary" value="db2" />
<property name="openjpa.DataCache" value="true" />
<property name="openjpa.Log"
value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>