Java 如何使用jdbc准备的语句将SqlDescriptor写入tsrange列?
我按照优秀的指南将特殊的sql类型Java 如何使用jdbc准备的语句将SqlDescriptor写入tsrange列?,java,postgresql,hibernate,jdbc,Java,Postgresql,Hibernate,Jdbc,我按照优秀的指南将特殊的sql类型tsrange映射到hibernate。我决定使用Java和SQL描述符,而不是用户类型,因为JDBCSQL处理应该更好 当我试图持久化一个列名为time range且类型为tsrange的实体时,我总是得到:错误[org.hibernate.engine.jdbc.spi.SqlExceptionHelper](默认任务2)错误:列“time_range”的类型为tsrange,但表达式的类型为character variable Hinweis:您需要重写或
tsrange
映射到hibernate。我决定使用Java和SQL描述符,而不是用户类型,因为JDBCSQL处理应该更好
当我试图持久化一个列名为time range且类型为tsrange的实体时,我总是得到:错误[org.hibernate.engine.jdbc.spi.SqlExceptionHelper](默认任务2)错误:列“time_range”的类型为tsrange,但表达式的类型为character variable
Hinweis:您需要重写或强制转换表达式。
我的理解是,我需要用setObject方法和type.OTHER或type.JAVA_对象编写一个特殊/非标准的sql类型。将范围sql类型放入PreparedStatement的首选方式是什么
BasicBinder源代码,我在其中填写jdbc准备好的语句,sqlString包含“[2019-01-14 13:06:262019-01-14 13:12:39]”
:
我找到了解决办法。
tsrange
可以作为字符串写入“[2019-01-14 13:06:262019-01-14 13:12:39]”
到PreparedStatement st
中,格式为st.setObject(index,sqlString,Type.OTHER)代码>
以下是正在工作的TsRangeSqlTypeDescriptor
类:
package com.example.galea.model.types;
import java.lang.reflect.InvocationTargetException;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
public class TsRangeSqlTypeDescriptor implements SqlTypeDescriptor {
/** */
private static final long serialVersionUID = -4377165492827156136L;
private static final Log log = LogFactory.getLog(TsRangeSqlTypeDescriptor.class);
public static final TsRangeSqlTypeDescriptor INSTANCE = new TsRangeSqlTypeDescriptor();
@Override
public int getSqlType() {
return Types.OTHER; // <--- This is importand!
}
@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 {
String sqlString = javaTypeDescriptor.toString(value);
// Here is the solution with Type.OTHER
st.setObject(index, sqlString, getSqlType());
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException {
st.setObject(name, javaTypeDescriptor.toString(value));
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>(javaTypeDescriptor, this) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
if(javaTypeDescriptor instanceof TsRangeJavaTypeDescriptor) {
TsRangeJavaTypeDescriptor rangeJavaTypeDescriptor = (TsRangeJavaTypeDescriptor) javaTypeDescriptor;
Object pgObject = rs.getObject(name);
Object valueRaw;
// Ugly, but I can not cast PGobject
try {
valueRaw = pgObject.getClass().getMethod(getValue, null).invoke(pgObject);
if(valueRaw instanceof String) {
String value = (String) valueRaw;
return (X) rangeJavaTypeDescriptor.wrap(value, options);
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
log.error(Failed to parse pgObject,e);
}
}
return javaTypeDescriptor.wrap(rs.getObject(name), options);
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap(statement.getObject(index), options);
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap(statement.getObject(name), options);
}
};
}
}
package com.example.galea.model.types;
导入java.lang.reflect.InvocationTargetException;
导入java.sql.CallableStatement;
导入java.sql.PreparedStatement;
导入java.sql.ResultSet;
导入java.sql.SQLException;
导入java.sql.Types;
导入org.apache.commons.logging.Log;
导入org.apache.commons.logging.LogFactory;
导入org.hibernate.type.descriptor.ValueBinder;
导入org.hibernate.type.descriptor.ValueExtractor;
导入org.hibernate.type.descriptor.WrapperOptions;
导入org.hibernate.type.descriptor.java.JavaTypeDescriptor;
导入org.hibernate.type.descriptor.sql.BasicBinder;
导入org.hibernate.type.descriptor.sql.BasicExtractor;
导入org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
公共类TsRangeSqlTypeDescriptor实现SqlTypeDescriptor{
/** */
私有静态最终长serialVersionUID=-4377165492827156136L;
私有静态最终日志日志=LogFactory.getLog(TsRangeSqlTypeDescriptor.class);
公共静态最终TsRangeSqlTypeDescriptor实例=新的TsRangeSqlTypeDescriptor();
@凌驾
public int getSqlType(){
返回类型。其他;//
Hibernate类型项目提供了一种支持PostgreSQLTSRANGE
列类型的方法
您需要做的第一件事是使用以下Maven依赖项:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Vladmichalcea网站
hibernate-types-52
${hibernate types.version}
之后,您可以像这样映射PostgreSQL范围:
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
typeClass = PostgreSQLRangeType.class,
defaultForType = Range.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
private String title;
@Column(
name = "price_cent_range",
columnDefinition = "numrange"
)
private Range<BigDecimal> priceRange;
@Column(
name = "discount_date_range",
columnDefinition = "daterange"
)
private Range<LocalDate> discountDateRange;
//Getters and setters omitted for brevity
}
@实体(name=“Book”)
@表(name=“book”)
@类型定义(
typeClass=PostgreSQLRangeType.class,
defaultForType=Range.class
)
公共课堂用书{
@身份证
@生成值
私人长id;
@归化
专用字符串isbn;
私有字符串标题;
@纵队(
name=“价格/分/范围”,
columnDefinition=“numrange”
)
私人范围价格范围;
@纵队(
name=“折扣日期范围”,
columnDefinition=“日期范围”
)
私人范围折扣日期范围;
//为简洁起见省略了getter和setter
}
Range
和PostgreSQLRangeType
类来自Hibernate类型项目
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
typeClass = PostgreSQLRangeType.class,
defaultForType = Range.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
private String title;
@Column(
name = "price_cent_range",
columnDefinition = "numrange"
)
private Range<BigDecimal> priceRange;
@Column(
name = "discount_date_range",
columnDefinition = "daterange"
)
private Range<LocalDate> discountDateRange;
//Getters and setters omitted for brevity
}