JPA 2.1带条件的多个条件连接

时间:2016-09-14 07:39:12

标签: java jpa left-join criteria-api

我使用带有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>

0 个答案:

没有答案