I am running a JUnit test case to test the functionality out. The test case first sets up the data. A category with another category within it. The inner category has one product. The product is related to two skus. The formula needs to calculate the min(sku.price) and assign it to the lowestPrice property. The test case prints the value of the lowestPrice and finally the test case deletes all the data fed to the database for peforming the test.
Complete mapping files for Product and Sku:
Code:
<!-- PRODUCT -->
<class name="Product" table="product">
<id name="id" unsaved-value="null" type="string" length="32">
<generator class="uuid"/>
</id>
<version name="version" type="long" unsaved-value="null"/>
<property name="name" type="string" not-null="true" unique="true"/>
<property name="shippingPrice" type="double" not-null="true"/>
<property name="lowestPrice" type="double">
<formula>
(
select min(sku.price)
from Product as prod, Sku as sku
where prod.id = sku.productId
)
</formula>
</property>
<map name="descriptions"
access="field"
lazy="true"
cascade="all">
<key column="entityId" foreign-key="none"/>
<map-key formula="type" type="string" length="32"/>
<one-to-many class="Description"/>
</map>
<property name="discontinued" type="boolean" not-null="true"/>
<property name="active" type="boolean" not-null="true"/>
<set name="skus" access="field" lazy="true" cascade="all" inverse="true">
<key column="productId" not-null="true"/>
<one-to-many class="Sku"/>
</set>
<set name="parentCategories" access="field" table="category_product" inverse="true" lazy="true">
<key column="productId" not-null="true"/>
<many-to-many column="categoryId"
class="Category"/>
</set>
<map name="flags"
access="field"
table="product_flag"
cascade="all"
lazy="true">
<key column="productId" not-null="true"/>
<index column="name" type="string" length="32"/>
<element column="value" type="boolean" not-null="true"/>
</map>
</class>
<!-- SKU -->
<class name="Sku" table="sku">
<id name="id" unsaved-value="null" type="string" length="32">
<generator class="uuid"/>
</id>
<version name="version" type="long" unsaved-value="null"/>
<property name="partNumber" type="string" not-null="true" unique="true"/>
<property name="manufacturePN" type="string"/>
<property name="weight" type="double"/>
<property name="price" type="double" not-null="true"/>
<property name="msrp" type="double"/>
<property name="displayName" type="string" not-null="true"/>
<property name="active" type="boolean" not-null="true"/>
<property name="discontinued" type="boolean" not-null="true"/>
<many-to-one
name="product"
column="productId"
class="Product" not-null="true"/>
</class>
Generated sql:
Code:
INFO - Hibernate 3.0
INFO - hibernate.properties not found
INFO - using CGLIB reflection optimizer
INFO - using JDK 1.4 java.sql.Timestamp handling
INFO - configuring from resource: /hibernate.cfg.xml
INFO - Configuration resource: /hibernate.cfg.xml
INFO - Mapping resource: com/ac/tan/beans/Beans.hbm.xml
INFO - Mapping class: com.ac.tan.beans.Category -> category
INFO - Mapping collection: com.ac.tan.beans.Category.products -> category_product
INFO - Mapping class: com.ac.tan.beans.Description -> description
INFO - Mapping class: com.ac.tan.beans.Product -> product
INFO - Mapping collection: com.ac.tan.beans.Product.parentCategories -> category_product
INFO - Mapping collection: com.ac.tan.beans.Product.flags -> product_flag
INFO - Mapping class: com.ac.tan.beans.Sku -> sku
INFO - Mapping class: com.ac.tan.beans.Contact -> contact
INFO - Mapping class: com.ac.tan.beans.Customer -> customer
INFO - Mapping class: com.ac.tan.beans.Cart -> cart
INFO - Mapping class: com.ac.tan.beans.CartItem -> cartitem
INFO - Mapping class: com.ac.tan.beans.CreditCard -> creditcard
INFO - Mapping class: com.ac.tan.beans.OrderItem -> orderitem
INFO - Mapping class: com.ac.tan.beans.Destination -> destination
INFO - Mapping class: com.ac.tan.beans.OrderItemDestination -> orderitem_destination
INFO - Mapping class: com.ac.tan.beans.Order -> order
INFO - Configured SessionFactory: null
INFO - processing extends queue
INFO - processing collection mappings
INFO - Mapping collection: com.ac.tan.beans.Category.subCategories -> category
INFO - Mapping collection: com.ac.tan.beans.Product.descriptions -> description
INFO - Mapping collection: com.ac.tan.beans.Product.skus -> sku
INFO - Mapping collection: com.ac.tan.beans.Customer.contacts -> contact
INFO - Mapping collection: com.ac.tan.beans.Customer.orders -> order
INFO - Mapping collection: com.ac.tan.beans.Customer.creditCards -> creditcard
INFO - Mapping collection: com.ac.tan.beans.Cart.cartItems -> cartitem
INFO - Mapping collection: com.ac.tan.beans.OrderItem.orderItemDestinations -> orderitem_destination
INFO - Mapping collection: com.ac.tan.beans.Destination.orderItemDestinations -> orderitem_destination
INFO - Mapping collection: com.ac.tan.beans.Order.orderItems -> orderitem
INFO - Mapping collection: com.ac.tan.beans.Order.destinations -> destination
INFO - processing association property references
INFO - processing foreign key constraints
INFO - Using dialect: org.hibernate.dialect.MySQLDialect
INFO - Maximum outer join fetch depth: 2
INFO - Default batch fetch size: 1
INFO - Generate SQL with comments: disabled
INFO - Order SQL updates by primary key: disabled
INFO - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
INFO - Using ASTQueryTranslatorFactory
INFO - Query language substitutions: {}
INFO - C3P0 using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost/test3
INFO - Connection properties: {user=someUser, password=****}
INFO - autocommit mode: false
Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@12bb7e0 [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@15a0305 [ acquireIncrement -> 3, autoCommitOnClose -> false, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, maxIdleTime -> 0, maxPoolSize -> 15, maxStatements -> 0, minPoolSize -> 3, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@134f69a [ description -> null, driverClass -> null, factoryClassLocation -> null, jdbcUrl -> jdbc:mysql://localhost/test3, properties -> {user=someUser, password=*******} ] , propertyCycle -> 300, testConnectionOnCheckout -> false ] , factoryClassLocation -> null, numHelperThreads -> 3 ]
INFO - JDBC batch size: 15
INFO - JDBC batch updates for versioned data: disabled
INFO - Scrollable result sets: enabled
INFO - JDBC3 getGeneratedKeys(): enabled
INFO - Transaction strategy: org.hibernate.transaction.JDBCTransactionFactory
INFO - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
INFO - Automatic flush during beforeCompletion(): disabled
INFO - Automatic session close at end of transaction: disabled
INFO - Cache provider: org.hibernate.cache.EhCacheProvider
INFO - Second-level cache: enabled
INFO - Optimize cache for minimal puts: disabled
INFO - Structured second-level cache entries: enabled
INFO - Query cache: disabled
INFO - Echoing all SQL to stdout
INFO - Statistics: disabled
INFO - Deleted entity synthetic identifier rollback: disabled
INFO - Default entity-mode: pojo
INFO - building session factory
WARN - No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/C:/Documents%20and%20Settings/mkhumri/Development/tan/default-site/WEB-INF/lib/ehcache-1.1.jar!/ehcache-failsafe.xml
INFO - Not binding factory to JNDI, no JNDI name configured
INFO - Using dialect: org.hibernate.dialect.MySQLDialect
INFO - C3P0 using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost/test3
INFO - Connection properties: {user=someUser, password=****}
INFO - autocommit mode: false
INFO - Running hbm2ddl schema update
INFO - fetching database metadata
Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@64ab4d [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@49d67c [ acquireIncrement -> 3, autoCommitOnClose -> false, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, maxIdleTime -> 0, maxPoolSize -> 15, maxStatements -> 0, minPoolSize -> 3, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@12a55aa [ description -> null, driverClass -> null, factoryClassLocation -> null, jdbcUrl -> jdbc:mysql://localhost/test3, properties -> {user=someUser, password=*******} ] , propertyCycle -> 300, testConnectionOnCheckout -> false ] , factoryClassLocation -> null, numHelperThreads -> 3 ]
INFO - updating schema
INFO - processing extends queue
INFO - processing collection mappings
INFO - processing association property references
INFO - processing foreign key constraints
INFO - table found: .order
INFO - columns: [creditcardid, id, customerid, version]
INFO - foreign keys: [fk651874e1d2dfd4a, fk651874e65ee8540]
INFO - indexes: [primary, fk651874e1d2dfd4a, fk651874e65ee8540]
INFO - table found: .cart
INFO - columns: [id, version]
INFO - foreign keys: []
INFO - indexes: [primary]
INFO - table found: .cartitem
INFO - columns: [cartid, skuid, quantity, id, version]
INFO - foreign keys: [fk6d663383a1cce, fk6d6633cf9dd842]
INFO - indexes: [primary, fk6d663383a1cce, fk6d6633cf9dd842]
INFO - table found: .category
INFO - columns: [parentid, description, image, name, id, version]
INFO - foreign keys: [fk302bcfea059c036]
INFO - indexes: [fk302bcfea059c036, primary]
INFO - table found: .category_product
INFO - columns: [productid, categoryid]
INFO - foreign keys: [fkb88a52aea795af8a, fkb88a52aee3396ce6]
INFO - indexes: [fkb88a52aea795af8a, primary, fkb88a52aee3396ce6]
INFO - table found: .contact
INFO - columns: [phonenumber, first, id, entitytype, version, company, street2, last, street1, entityid, emailaddress, state, zip, city]
INFO - foreign keys: []
INFO - indexes: [primary]
INFO - table found: .creditcard
INFO - columns: [cardtype, cardnumber, nameoncard, expiry, id, version, customerid, street2, street1, securitycode, state, zip, city]
INFO - foreign keys: [fkde6401891d2dfd4a]
INFO - indexes: [fkde6401891d2dfd4a, cardnumber, primary]
INFO - table found: .customer
INFO - columns: [password, last, first, emailaddress, id, company, version]
INFO - foreign keys: []
INFO - indexes: [primary, emailaddress]
INFO - table found: .description
INFO - columns: [text, type, entityid, entitytype, id, version]
INFO - foreign keys: []
INFO - indexes: [primary]
INFO - table found: .destination
INFO - columns: [phonenumber, first, orderid, id, version, company, street2, last, street1, emailaddress, state, zip, city]
INFO - foreign keys: [fkaac6440e96bb4d24]
INFO - indexes: [primary, fkaac6440e96bb4d24]
INFO - table found: .orderitem
INFO - columns: [price, description, orderid, partnumber, quantity, id, version]
INFO - foreign keys: [fke8b2ab6196bb4d24]
INFO - indexes: [primary, fke8b2ab6196bb4d24]
INFO - table found: .orderitem_destination
INFO - columns: [destinationid, orderitemid, quantity, id, version]
INFO - foreign keys: [fkd862443050c470e4, fkd862443017c122a]
INFO - indexes: [primary, fkd862443017c122a, fkd862443050c470e4]
INFO - table found: .product
INFO - columns: [active, shippingprice, discontinued, name, id, version]
INFO - foreign keys: []
INFO - indexes: [primary, name]
INFO - table found: .product_flag
INFO - columns: [value, productid, name]
INFO - foreign keys: [fk3c72a8bce3396ce6]
INFO - indexes: [fk3c72a8bce3396ce6, primary]
INFO - table found: .sku
INFO - columns: [active, productid, manufacturepn, price, discontinued, partnumber, displayname, weight, id, msrp, version]
INFO - foreign keys: [fk1bd1de3396ce6]
INFO - indexes: [primary, fk1bd1de3396ce6, partnumber]
INFO - schema update complete
INFO - Checking 0 named queries
Hibernate: insert into category (version, name, description, image, parentId, id) values (?, ?, ?, ?, ?, ?)
Hibernate: select category0_.id as col_0_0_ from category category0_ where (category0_.name=?)
Hibernate: insert into category (version, name, description, image, parentId, id) values (?, ?, ?, ?, ?, ?)
Hibernate: update category set version=?, name=?, description=?, image=?, parentId=? where id=? and version=?
Hibernate: select category0_.id as col_0_0_ from category category0_ where (category0_.name=?)
Hibernate: insert into category (version, name, description, image, parentId, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into product (version, name, shippingPrice, discontinued, active, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into description (version, type, text, entityType, entityId, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into sku (version, partNumber, manufacturePN, weight, price, msrp, displayName, active, discontinued, productId, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into sku (version, partNumber, manufacturePN, weight, price, msrp, displayName, active, discontinued, productId, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update category set version=?, name=?, description=?, image=?, parentId=? where id=? and version=?
Hibernate: insert into category_product (categoryId, productId) values (?, ?)
Hibernate: update description set entityId=? where id=?
Hibernate: insert into product_flag (productId, name, value) values (?, ?, ?)
#DEBUG: lowest price = null
Hibernate: select category0_.id as col_0_0_ from category category0_ where (category0_.name=?)
Hibernate: delete from category_product where categoryId=?
Hibernate: update description set entityId=null where entityId=?
Hibernate: delete from product_flag where productId=?
Hibernate: delete from description where id=? and version=?
Hibernate: delete from sku where id=? and version=?
Hibernate: delete from sku where id=? and version=?
Hibernate: delete from product where id=? and version=?
Hibernate: delete from category where id=? and version=?
Hibernate: delete from category where id=? and version=?
Hibernate: delete from category where id=? and version=?
JUnit test case:
Code:
public void testProductLowestPrice()
{
DBManager.beginTransaction();
try
{
CategoryDAO cdao = daoFactory.getCategoryDAO();
SkuDAO sdao = daoFactory.getSkuDAO();
ProductDAO pdao = daoFactory.getProductDAO();
Category cat = new Category("Audio",
"This category maintains the audio products.", null);
cdao.insert(cat);
Iterator it = cdao.findAllByName("Audio");
Category p = (it != null && it.hasNext())? (Category)it.next() : null;
cat = new Category("Bose",
"This category maintains the bose products.", "bose-logo.jpg");
p.addSubCategory(cat);
cdao.insert(cat);
cdao.update(p);
it = cdao.findAllByName("Bose");
Category p1 = (it != null && it.hasNext())? (Category)it.next() : null;
Category cat1 = new Category("Bose-xtinct",
"This category maintains the bose products for cars.",
"bose-xtinct.jpg");
Product pr1 = new Product("Prod1", new Double(9.5), true, false);
pr1.addDescription(new Description(Description.SHORT,
"Bose with advanced sub woofer and trebble."));
pr1.addFlag("doNotDisplay", true);
Sku sku1 = new Sku("prd-765", "bing ling ding", "bing ling", 128.9,
89.79, 100, true, false);
Sku sku2 = new Sku("prd-09", "adfa adfa sda", "afd fdf", 11.9,
12, 50, true, false);
p1.addSubCategory(cat1);
pr1.addSku(sku1);
pr1.addSku(sku2);
cat1.addProduct(pr1);
String catId = cdao.insert(cat1);
cdao.update(p1);
sdao.insert(sku1);
sdao.insert(sku2);
DBManager.commitTransaction();
DBManager.beginTransaction();
pr1 = (Product)pdao.load(pr1.getId());
if(pr1.getLowestPrice() != null)
System.out.println("#DEBUG: lowest price = " + pr1.getLowestPrice().doubleValue());
else
System.out.println("#DEBUG: lowest price = null");
//Cleanup
Iterator it4 = cdao.findAllByName("Audio");
while(it4 != null && it4.hasNext())
{
Category delCategory = (Category)it4.next();
Category delCategoryParent = delCategory.getParent();
if (delCategoryParent != null)
{
delCategoryParent.removeSubCategory(delCategory);
}
cdao.delete(delCategory);
}
DBManager.commitTransaction();
}
catch (Exception ex)
{
ex.printStackTrace();
DBManager.rollbackTransaction();
Assert.fail();
}
}