Home > database >  What is the best practice to store a specification of an Entity in Spring?
What is the best practice to store a specification of an Entity in Spring?

Time:06-25

My database contain products in a single table called Product, and each product might have certain fields with their specification, e.g.

//Bicycle product
{
    "name" : "Bicycle",
    "category" : "Bicycles"
    "specification" : {
        "color" : "red"
    }
}

//Wheel product
{
    "name" : "Wheel",
    "category" : "Spare Parts",
    "specification" : {
        "diameter" : "7.5"
    }
}

So i've come up with idea of making a field of type Map<String, String> (which creates a another table called specifications) in my Product entity to contain those specifications. But i don't like this approach, because all of the additional fields would be of String type, and because Spring will create a bean out of this field, I wont be able to specify the type of value as an abstract class (like this Map<String, Object>).

I thought of creating additional fields, like this:

@ElementCollection
    private Map<String, String> string_features;
@ElementCollection
    private Map<String, Double> double_features;
// ...

But it looks kind of ugly and I think there is a better way to do it. And also, if the specification field is of a different Entity type, I will have to create another map for that specific entity, e.g.

//Bicycle product
{
    "name" : "Bicycle",
    "category" : "Bicycles"
    "specification" : {
        "color" : "red",
        "wheel" : {
            "name" : "Wheel",
        }
    }
}

CodePudding user response:

If the value can be only be numbers and strings, maybe you can save the value as strings and then use a regex to check if the string is a number before returning the value.

Otherwise, you need a way to recognize the type. I think I would change it to this:

//Bicycle product
{
    "name" : "Bicycle",
    "category" : "Bicycles"
    "specifications" : [
        { name: "color", value: "red", type: "string"},
        { name: "diameter", value: "7.5", type: "double"},
        ...
     ]
}

You can map this has:

@ElementCollection
private List<Specification> specifications;

...

@Embaddable
class Specification {
   String name;
   String value;
   String type;

   // ... getter/setter and everything else

   @Transient
   Object getConvertedValue() {
      if ("double".equals(type)) {
          return Double.parse(value);
      }
      // String is the default
      return value;
   }
}

The nice thing is that you can have as many types as you want.

By the way, I've decided to keep it simple and map the type as String. But there is probably a way to define it as Class<?> type and then read the value as type.cast(value).

  • Related