Hibernate version:
3.3.1 GA
Name and version of the database you are using:
MySQL 5
The generated SQL (show_sql=true):
Hibernate: insert into product_type (name) values (?)
Hibernate: insert into attribute_definition (name, product_type_id) values (?, ?)
Hibernate: insert into attribute_definition (name, product_type_id) values (?, ?)
Hibernate: insert into attribute_definition (name, product_type_id) values (?, ?)
Hibernate: insert into attribute_definition (name, product_type_id) values (?, ?)
Hibernate: insert into attribute_definition (name, product_type_id) values (?, ?)
Hibernate: insert into product (brand, cond, long_description, model_no, price, product_type_id, short_description, sku, title, upc) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into attribute (name, product_id, value) values (?, ?, ?)
Hibernate: insert into attribute (name, product_id, value) values (?, ?, ?)
Hibernate: insert into attribute (name, product_id, value) values (?, ?, ?)
Hibernate: insert into attribute (name, product_id, value) values (?, ?, ?)
Hibernate: insert into attribute (name, product_id, value) values (?, ?, ?)
I am developing a model that supports arbitrary attributes. Concretely, a Product can have one or more attributes in addition to standard fare (title, description, modelNo, sku, etc). The extra attributes are based off a ProductType, so for instance a Product could have a ProductType of "Laptop Computer"
Code:
ProductType type = new ProductType();
type.setName("Laptop Computer");
type.addAttributeDefinition(new AttributeDefinition("Screen Size"));
type.addAttributeDefinition(new AttributeDefinition("Screen Resolution"));
type.addAttributeDefinition(new AttributeDefinition("Processor Speed"));
type.addAttributeDefinition(new AttributeDefinition("RAM"));
type.addAttributeDefinition(new AttributeDefinition("Battery Life"));
productService.saveProductType(type);
Here is how I create the product:
Code:
Product product = new Product();
product.setTitle("Dell Precision M6300");
product.setBrand("Dell");
product.setCondition("New");
product.setModelNo("M6300");
product.setShortDescription("A perfect laptop for demanding users");
product.setProductType(type);
setProductType above isn't a standard setter. It does a little bit more:
Code:
public void setProductType(ProductType productType) {
this.productType = productType;
for (AttributeDefinition definition : productType.getAttributeDefinitions()) {
Attribute attribute = new Attribute();
attribute.setName(definition.getName());
attribute.setValue("")
attributes.put(attribute.getName(), attribute);
attribute.setProduct(this);
}
}
So a ProductType is responsible for defining attribute definitions through the AttributeDefinition class. When I want to set the value of actual attributes, I call this convenience method on Product:
Code:
public void setAttribute(String name, String value) {
if (!attributes.containsKey(name)) {
throw new IllegalArgumentException("no attribute with name " + name);
}
Attribute attribute = attributes.get(name);
attribute.setValue(value);
}
So I can do this:
Code:
product.setAttribute("Screen Size", "17in");
product.setAttribute("Screen Resolution", "1280x1024");
product.setAttribute("Processor Speed", "2.80 Ghz");
product.setAttribute("RAM", "8 Gb");
product.setAttribute("Battery Life", "30 minutes");
After setting these attributes, I do a productService.saveProduct(product). The product gets written to the DB as do the attributes, but curiously, the name property of Attribute is saved while the value property is not. The strange thing is that if I call saveProduct() both before and after the code above, both values are saved correctly. I don't understand what's going on.
Here is the full listing of what I am doing:
Code:
ProductType type = new ProductType();
type.setName("Laptop Computer");
type.addAttributeDefinition(new AttributeDefinition("Screen Size"));
type.addAttributeDefinition(new AttributeDefinition("Screen Resolution"));
type.addAttributeDefinition(new AttributeDefinition("Processor Speed"));
type.addAttributeDefinition(new AttributeDefinition("RAM"));
type.addAttributeDefinition(new AttributeDefinition("Battery Life"));
productService.saveProductType(type);
// create a product
Product product = new Product();
product.setTitle("Dell Precision M6300");
product.setBrand("Dell");
product.setCondition("New");
product.setModelNo("M6300");
product.setShortDescription("A perfect laptop for demanding users");
product.setProductType(type);
// additional attributes
product.setAttribute("Screen Size", "17in");
product.setAttribute("Screen Resolution", "1280x1024");
product.setAttribute("Processor Speed", "2.80 Ghz");
product.setAttribute("RAM", "8 Gb");
product.setAttribute("Battery Life", "30 minutes");
productService.saveProduct(product); // the attribute keys are saved but not the values
Here is what the DB looks like:
Code:
mysql> select * from attribute;
+----+-------------------+-------+------------+
| id | name | value | product_id |
+----+-------------------+-------+------------+
| 1 | Processor Speed | NULL | 1 |
| 2 | RAM | NULL | 1 |
| 3 | Screen Resolution | NULL | 1 |
| 4 | Screen Size | NULL | 1 |
| 5 | Battery Life | NULL | 1 |
+----+-------------------+-------+------------+
I can list the mappings if it would help. But, the fact that I am mutating the state of the attributes _before_ saving the parent to the DB and getting these results makes me think I just don't understand some base behavior. Why if I do the save prior to setting the attribute values, then again after, do I get the updates? Shouldn't it all happen on the first set of inserts?
John