I need to persist BigDecimal[][] type to MySQL database by using Hibernate. I dont know how to do it. I tried this:
@Getter
@Setter
@ToString
@RequiredArgsConstructor
@Embeddable
@TypeDef(name = "coordinates_array",
typeClass = BigDecimalArrayType.class)
public class Geometry {
private String type;
@Type(
type = "coordinates_array",
parameters = @org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "BigDecimal"
)
)
@Column(
name = "coordinates",
columnDefinition = "BigDecimal[][]"
)
BigDecimal[][] coordinates;}
There is no BigDecimalArrayType class. How can i define BigDecimalArrayType? Or is there anything else we can substitute for it?
CodePudding user response:
As mentioned in my comment, since you do not want to save the array in a "plain text" way you can follow this way.
Use two fields, one will be persistent (part of the DB) and the other will be transient (part only of the app logic).
Persistent will be the byte[]
of your CoordinateHolder
and transient will be the BigDecimal[][]
.
Here is the class of the CoordinateHolder
. As you see I am using @Transient
to disallow a field to be persisted.
@Embeddable
public class CoordinateHolder implements Serializable
{
@Transient
private BigDecimal[][] transientCoordinates; // Will not be saved in the DB, is part only of the business logic.
public BigDecimal[][] getTransientCoordinates()
{
return transientCoordinates;
}
public void setTransientCoordinates(BigDecimal[][] transientCoordinates)
{
this.transientCoordinates = transientCoordinates;
}
}
After this let's take a look at the entity class:
@Entity(name = "test_name")
public class TestEntity
{
// Your id...
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Embedded
private CoordinateHolder coordinateHolder;
@Lob
@Column(name = "coordinates", columnDefinition = "BLOB")
private byte[] blobCoordinates;
public void setCoordinates(BigDecimal[][] arr)
{
if (coordinateHolder == null)
{
coordinateHolder = new CoordinateHolder();
}
coordinateHolder.setTransientCoordinates(arr);
}
public BigDecimal[][] getCoordinates()
{
if (coordinateHolder == null)
{
return null;
}
return coordinateHolder.getTransientCoordinates();
}
// This can also be done through Entity listeners which actually do the same thing
// Pre persist is always performed before persisting this entity
@PrePersist
public void prePersisting()
{
System.out.println("Hey I am being persisted. And now I am turning my transient coordinates into BLOB for the db");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out;
try
{
out = new ObjectOutputStream(bos);
out.writeObject(coordinateHolder);
out.flush();
blobCoordinates = bos.toByteArray();
} catch (Exception e)
{
// Do smth with your exception...
e.printStackTrace();
} finally
{
try
{
bos.close();
} catch (IOException ignored)
{
// ignore close exception
}
}
}
// Perform after loading...
@PostLoad
public void postLoading()
{
System.out.println("Hey I am being fetched, I am turning my BLOB into the array holder so that you can use it in your app");
ByteArrayInputStream bis = new ByteArrayInputStream(this.getBlobCoordinates());
ObjectInput in = null;
try
{
in = new ObjectInputStream(bis);
CoordinateHolder o = (CoordinateHolder) in.readObject();
this.setCoordinateHolder(o);
}
catch (Exception e)
{
// Do smth with your exception...
e.printStackTrace();
}
finally
{
try
{
if (in != null)
{
in.close();
}
} catch (IOException ex)
{
// ignore close exception
}
}
}
... Further getters and setters...
}
The code is described with comments and it should be understandable. This makes it possible for you to persist what you need.
CodePudding user response:
Maybe you can transform your BigDecimal[][] onto a blob if you want to persist is as it is, instead of breaking up the rows/columns onto proper tables.