2012-05-08 9 views
7

En nuestra lógica comercial tenemos que manejar los valores Double.Infinity positivos y negativos, así como los valores Double.NaN.Almacenamiento de valores Java Double Infinity y NaN en la base de datos MS SQL 2008

Tenemos que almacenar estos valores en la base de datos de Microsot SQL Server 2008. El problema es que Microsot SQL Server no admite valores infinitos o nan. (Problem description for SQL Server 2005, también aplicable para MS SQL Server 2008).

Estamos utilizando Hibernate 3.6.7 como nuestra implementación JPA y el controlador sqljdbc4 de Microsoft versión 4.0.2206.100.

Hemos tratado de resolver este problema estableciendo definición de columna de APP entidad a VARCHAR como esto

@Column(columnDefinition = "VARCHAR(40)") 
private Double foo; 

Esto no parece tener ningún efecto, a pesar de que la definición de columna se cambia adecuadamente a VARCHAR en la base de datos. Parece que el valor infinito está atrapado en la validación del controlador JDBC ya que tenemos el siguiente StackTrace al intentar insertar Double.Infinity valor:

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 6 (""): The supplied value is not a valid instance of data type float. Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision. 
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216) 
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1515) 
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:404) 
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:350) 
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696) 
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715) 
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:180) 
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:155) 
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:314) 
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94) 
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57) 
    ... 79 more 

Alguna idea de cómo solucionar este problema son bienvenidos.

Respuesta

1

Aquí hay una solución simple para este problema: Use String para el tipo de campo y realice la conversión en getters y setters. De esta forma no tiene que cambiar la lógica de su negocio y la lógica de transformación real se encapsula muy bien.

// Column definition is not a necessity here 
@Column(columnDefinition = "VARCHAR(40)") 
private String foo; 

public Double getFoo() { 
    return this.foo != null ? Double.valueOf(this.foo) : null; 
} 

public void setFoo(Double d) { 
    this.foo = d != null ? d.toString() : null; 
} 
+1

Esto parece una solución adecuada para el problema. La única limitación es que dado que el valor es como VARCHAR en la base de datos, es posible que no pueda realizar cálculos para los valores en SQL. – Spaideri

Cuestiones relacionadas