In this article, Ich habe erklärt, wie Sie einen generischen Array-Typ entwickeln können, den Sie einfach an verschiedene spezifische Typen wie String[]
oder int[]
anpassen können.
Sie müssen all diese Typen nicht manuell erstellen, geben Sie einfach sie über Maven Zentrale mit der folgenden Abhängigkeit erhalten können:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Für weitere Informationen, besuchen Sie die hibernate-types open-source project.
Vorausgesetzt, dass Sie diese Tabelle in Ihrer Datenbank haben:
create table event (
id int8 not null,
version int4,
sensor_names text[],
sensor_values integer[],
primary key (id)
)
Und wollen Sie es wie folgt zuzuordnen:
@Entity(name = "Event")
@Table(name = "event")
@TypeDefs({
@TypeDef(
name = "string-array",
typeClass = StringArrayType.class
),
@TypeDef(
name = "int-array",
typeClass = IntArrayType.class
)
})
public static class Event
extends BaseEntity {
@Type(type = "string-array")
@Column(
name = "sensor_names",
columnDefinition = "text[]"
)
private String[] sensorNames;
@Type(type = "int-array")
@Column(
name = "sensor_values",
columnDefinition = "integer[]"
)
private int[] sensorValues;
//Getters and setters omitted for brevity
}
Sie müssen die StringArrayType
wie folgt definieren:
public class StringArrayType
extends AbstractSingleColumnStandardBasicType<String[]>
implements DynamicParameterizedType {
public StringArrayType() {
super(
ArraySqlTypeDescriptor.INSTANCE,
StringArrayTypeDescriptor.INSTANCE
);
}
public String getName() {
return "string-array";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
@Override
public void setParameterValues(Properties parameters) {
((StringArrayTypeDescriptor)
getJavaTypeDescriptor())
.setParameterValues(parameters);
}
}
Sie müssen diedefinierenwie folgt aus:
public class IntArrayType
extends AbstractSingleColumnStandardBasicType<int[]>
implements DynamicParameterizedType {
public IntArrayType() {
super(
ArraySqlTypeDescriptor.INSTANCE,
IntArrayTypeDescriptor.INSTANCE
);
}
public String getName() {
return "int-array";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
@Override
public void setParameterValues(Properties parameters) {
((IntArrayTypeDescriptor)
getJavaTypeDescriptor())
.setParameterValues(parameters);
}
}
Sowohl die Streich- und Int-Typen teilen die ArraySqlTypeDescriptor
:
public class ArraySqlTypeDescriptor
implements SqlTypeDescriptor {
public static final ArraySqlTypeDescriptor INSTANCE =
new ArraySqlTypeDescriptor();
@Override
public int getSqlType() {
return Types.ARRAY;
}
@Override
public boolean canBeRemapped() {
return true;
}
@Override
public <X> ValueBinder<X> getBinder(
JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>(javaTypeDescriptor, this) {
@Override
protected void doBind(
PreparedStatement st,
X value,
int index,
WrapperOptions options
) throws SQLException {
AbstractArrayTypeDescriptor<Object> abstractArrayTypeDescriptor =
(AbstractArrayTypeDescriptor<Object>)
javaTypeDescriptor;
st.setArray(
index,
st.getConnection().createArrayOf(
abstractArrayTypeDescriptor.getSqlArrayType(),
abstractArrayTypeDescriptor.unwrap(
value,
Object[].class,
options
)
)
);
}
@Override
protected void doBind(
CallableStatement st,
X value,
String name,
WrapperOptions options
) throws SQLException {
throw new UnsupportedOperationException(
"Binding by name is not supported!"
);
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(
final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>(javaTypeDescriptor, this) {
@Override
protected X doExtract(
ResultSet rs,
String name,
WrapperOptions options
) throws SQLException {
return javaTypeDescriptor.wrap(
rs.getArray(name),
options
);
}
@Override
protected X doExtract(
CallableStatement statement,
int index,
WrapperOptions options
) throws SQLException {
return javaTypeDescriptor.wrap(
statement.getArray(index),
options
);
}
@Override
protected X doExtract(
CallableStatement statement,
String name,
WrapperOptions options
) throws SQLException {
return javaTypeDescriptor.wrap(
statement.getArray(name),
options
);
}
};
}
}
Sie müssen auch die Java-Deskriptoren definieren.
public class StringArrayTypeDescriptor
extends AbstractArrayTypeDescriptor<String[]> {
public static final StringArrayTypeDescriptor INSTANCE =
new StringArrayTypeDescriptor();
public StringArrayTypeDescriptor() {
super(String[].class);
}
@Override
protected String getSqlArrayType() {
return "text";
}
}
public class IntArrayTypeDescriptor
extends AbstractArrayTypeDescriptor<int[]> {
public static final IntArrayTypeDescriptor INSTANCE =
new IntArrayTypeDescriptor();
public IntArrayTypeDescriptor() {
super(int[].class);
}
@Override
protected String getSqlArrayType() {
return "integer";
}
}
Der größte Teil der Java-to-JDBC Typ Handhabung ist in der AbstractArrayTypeDescriptor
Basisklasse enthalten:
public abstract class AbstractArrayTypeDescriptor<T>
extends AbstractTypeDescriptor<T>
implements DynamicParameterizedType {
private Class<T> arrayObjectClass;
@Override
public void setParameterValues(Properties parameters) {
arrayObjectClass = ((ParameterType) parameters
.get(PARAMETER_TYPE))
.getReturnedClass();
}
public AbstractArrayTypeDescriptor(Class<T> arrayObjectClass) {
super(
arrayObjectClass,
(MutabilityPlan<T>) new MutableMutabilityPlan<Object>() {
@Override
protected T deepCopyNotNull(Object value) {
return ArrayUtil.deepCopy(value);
}
}
);
this.arrayObjectClass = arrayObjectClass;
}
@Override
public boolean areEqual(Object one, Object another) {
if (one == another) {
return true;
}
if (one == null || another == null) {
return false;
}
return ArrayUtil.isEquals(one, another);
}
@Override
public String toString(Object value) {
return Arrays.deepToString((Object[]) value);
}
@Override
public T fromString(String string) {
return ArrayUtil.fromString(
string,
arrayObjectClass
);
}
@SuppressWarnings({ "unchecked" })
@Override
public <X> X unwrap(
T value,
Class<X> type,
WrapperOptions options
) {
return (X) ArrayUtil.wrapArray(value);
}
@Override
public <X> T wrap(
X value,
WrapperOptions options
) {
if(value instanceof Array) {
Array array = (Array) value;
try {
return ArrayUtil.unwrapArray(
(Object[]) array.getArray(),
arrayObjectClass
);
}
catch (SQLException e) {
throw new IllegalArgumentException(e);
}
}
return (T) value;
}
protected abstract String getSqlArrayType();
}
AbstractArrayTypeDescriptor
auf ArrayUtil setzt die Java-Array tief Kopieren, Wickeln und Abwickeln Logik zu behandeln.
Jetzt, wenn Sie ein paar Entitäten einfügen;
Event nullEvent = new Event();
nullEvent.setId(0L);
entityManager.persist(nullEvent);
Event event = new Event();
event.setId(1L);
event.setSensorNames(
new String[] {
"Temperature",
"Pressure"
}
);
event.setSensorValues(
new int[] {
12,
756
}
);
entityManager.persist(event);
Hibernate die folgenden SQL-Anweisungen wird generieren:
INSERT INTO event (
version,
sensor_names,
sensor_values,
id
)
VALUES (
0,
NULL(ARRAY),
NULL(ARRAY),
0
)
INSERT INTO event (
version,
sensor_names,
sensor_values,
id
)
VALUES (
0,
{"Temperature","Pressure"},
{"12","756"},
1
)
Falls jemand frage mich, was das letzte Glied ist über (es ist jetzt eine 404), die Wayback Machine Link hier - http : //web.archive.org/web/20090325101739/http: //www.hibernate.org/393.html – Sam