I would like to ask how to store curve to DB. Curve object is represented by an array of points.
I have two options:
1) create two tables one for curve one for points
- it would look something like this:
CURVE[id]
,POINT[id, x, y, order, curve_id]
- I am not sure if this is optimal, to get one curve from database I would need to join to tables and in the POINT table there would be a lot of points
2) one curve = one row in one table
- I would store all data in one table for example like this: CURVE[id, data] where data could be in formate “[[1,2],[2,2],[3,4] …]” (string) or as blob or something like that.
What do you think? Is there any other option?
Advertisement
Answer
What you can do is to use javax.persistence.AttributeConverter and create curve converter like this:
public class CurveConverter implements AttributeConverter<Curve, String> { private static final String SEPARATOR1 = ","; private static final String SEPARATOR2 = ";"; @Override public String convertToDatabaseColumn(Curve curve) { if (curve == null) { return null; } StringBuilder sb = new StringBuilder(); for(CurvePoint curvePoint:curve.getPoints()){ sb.append(curvePoint.getTorque()); sb.append(SEPARATOR1); sb.append(curvePoint.getSpeed()); sb.append(SEPARATOR2); } sb.setLength(sb.length() - SEPARATOR2.length()); return sb.toString(); } @Override public Curve convertToEntityAttribute(String dbData) { if (dbData == null || dbData.isEmpty()) { return null; } String[] pieces = dbData.split(SEPARATOR2); if (pieces == null || pieces.length == 0) { return null; } List<CurvePoint> curvePoints = new ArrayList<>(); for(String piece:pieces){ String[] numbers = piece.split(SEPARATOR1); curvePoints.add(new CurvePoint(Float.parseFloat(numbers[0]), Float.parseFloat(numbers[1]))); } return Curve.builder().points(curvePoints).build(); } }
which will store your curve as string (CSV – “1.1,2.2;3.3,4.4 …”) to table as one attribute. You will get rid of joints and it will be faster. This is only good when the curve is immutable (all points are changing at once)
Then you just add annotation on field in entity where the curve is used like this:
@Column(name = "curve", length = 10000) @Basic(fetch = FetchType.LAZY) @Convert(converter = CurveConverter.class) Curve curve;
Important here is to set correct length of the string. Also check that @Basic(fetch = FetchType.LAZY)
is used to load the curve data lazy (only when we need them). The annotation @Convert(converter = CurveConverter.class)
then says to hibernate that before saving this field to database it will be converted using our newly created curve CurveConvertor (same when we will get the data from DB).