I use the EAV (Entity-Attribute-Value) pattern in an inventory management system I’m developing.
It’s very comparable to a typical webshop framework like Magento.
Attributes have a data type, like numeric, varchar, text.
The attribute definitions are stored in one table like eav_attributes. The values are stored in separate tables specific for the data type.
Say that a numeric attribute is assigned to a product. The database table that holds the relation between the attribute and product and the value, is a table like eav_decimal_attribute_values.
Example table scheme:
attribute_id | product_id | attribute_value (decimal)
And the same principle for a varchar attribute:
attribute_id | product_id | attribute_value (varchar(255))
When loading a product from the database, I load the product -> attribute -> value
relations of each of that tables.
So I query the eav_decimal_attribute_values table to get all assigned decimal attributes and their values for the product (or get an empty resultset or course).
And the same for the other attribute types (eav_varchar_attribute_values, eav_text_attribute_values, …).
So far this is actually the same as how e.g. Magento manages this.
Since I use a typed language, I chose to have the following design:
class AttributeDefinition
- string attributeName
- string attributeDescription
- enum dataType // Like 'numeric', 'varchar', 'text', ...
- ...
- ...
abstract class ProductAttributeAssignment
- AttributeDefinition attribute
class DecimalProductAttribute : ProductAttributeAssignment
- double value
- ...
class VarcharProductAttribute : ProductAttributeAssignment
- string value
- ...
class TextProductAttribute : ProductAttributeAssignment
- string value
- ...
Product
- name
- ...
- attributes
// Problematic part: storing different types together
- A TextProductAttribute
- Another TextProductAttribute
- A DecimalProductAttribute
- A VarcharProductAttribute
- ...
In code I want to preserve types. Like a numeric attribute’s value is stored as a double or decimal value in code. A varchar or text attribute is put in a string.
Of course I could just create one concrete class ProductAttributeAssignment, and store the value always as a string in memory, regardless of the data type the attribute represents. But imagine that I have to do calculations with numeric attributes, or search features like Charging cable length > 120, it would be useful to preserve types. Also when there would be features like developers could create plugins or hooks.
The problem is that I have some difficulties in coding the product aggregate. It would be logical to store a products’s attribute assignments just in a Product object. But since there’s a different class for each attribute type, I cannot just write a class like Product with a field List<…> attributes.
So, my question is not about storing things in the database/persistent layer, but about writing code for a business object that owns things that are actually the “same business thing” but technically different types in code.