Freitag, 11. Dezember 2009

Arithmetic operations using generic Hibernate Aliases

hibernate

I explained in my last blog Generic Joins with Hibernate Criteria how to create aliases for association paths. With the alias it's possible to get access to every attribute in your entity objects graph. Now I want to use an alias to create Projections with arithmetic operations. Therefore I use the method Projections.sqlProjection.
As the method name implies we have to use the SQL aliases instead of the Hibernate aliases. How do we get Hibernate generated SQL aliases before query execution. First thing is to create the alias for an association path as explained in Generic Joins with Hibernate Criteria. As next we need to get access to the CriteriaQueryTranslator which holds the SQL aliases. With CriteriaQueryTranslator.getSQLAlias( Criteria ) it's possible to get the sql alias. The SQL aliases can be directly used in the SQL projection. The following code calculates the total of an order with order items.

public class Order() {
    Set<OrderItem> orderItems = new HashSet<OrderItem>();
    ...
}

public class OrderItem() {
    private int quantity;
    private double price;
}

public class OrderDao() {

    public double getTotal() {
        Criteria criteria = new Critera(Order.class);
        String quantityAlias = createAlias( criteria, "orderItems.quantity);
        String priceAlias = createAlias( criteria, "orderItems.price");

        String quantitySQLAlias = getSqlAlias(criteria, quantityAlias);
        String priceSQLAlias = getSqlAlias(criteria, priceAlias);

        criteria.setProjection(Projections.sqlProjection( "sum(" + quantitySQLAlias + "*" + priceSQLAlias + ") as total", new String[] {"total"}, new Type[] {Hibernate.DOUBLE} ));
        return criteria.uniqueResult();
    }

    public static String getSqlAlias ( Criteria criteria, String alias )
    {
        CriteriaImpl criteriaImpl = ( CriteriaImpl ) criteria;
        SessionImplementor session = ( ( CriteriaImpl ) criteria ).getSession();
        SessionFactoryImplementor factory = session.getFactory();
        String[] implementors = factory.getImplementors( criteriaImpl.getEntityOrClassName() );

        CriteriaQueryTranslator translator = new CriteriaQueryTranslator( factory,
                ( CriteriaImpl ) criteria, implementors[ 0 ], CriteriaQueryTranslator.ROOT_SQL_ALIAS );

        String[] split = alias.split( "\\." );
        String path = split[ 0 ];
        String propertyName = split[ 1 ];

        Criteria aliasCriteria = findCriteriaForAlias( criteria, path );

        return translator.getSQLAlias( aliasCriteria ) + "." + propertyName;
    }

    public static Criteria findCriteriaForAlias ( Criteria criteria, String alias )
    {
        Iterator subcriterias = ( ( CriteriaImpl ) criteria )
                .iterateSubcriteria();
        while ( subcriterias.hasNext() )
        {
            Criteria subcriteria = ( Criteria ) subcriterias.next();
            if ( subcriteria.getAlias().equals( alias ) )
            {
                return subcriteria;
            }
        }
        return null;
    }

Keine Kommentare:

Kommentar veröffentlichen