2012-05-08 43 views
7

W naszej logice biznesowej musimy obsłużyć wartości dodatnie i ujemne Double.Infinity oraz wartości Double.NaN.Przechowywanie wartości Java Infinity i NaN w bazie danych MS SQL 2008

Musimy przechowywać te wartości w bazie danych Microsot SQL Server 2008. Problem polega na tym, że Microsot SQL Server nie obsługuje wartości nieskończoności lub nan. (Problem description for SQL Server 2005, dotyczy również MS SQL Server 2008).

Używamy Hibernate 3.6.7 jako naszej implementacji JPA i sterownika Microsoft sqljdbc4 w wersji 4.0.2206.100.

Staraliśmy się rozwiązać ten problem poprzez ustalenie definicji kolumny JPA podmiotu do VARCHAR jak ten

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

to nie wydaje się mieć żadnego wpływu, chociaż definicja kolumna jest odpowiednio zmieniona na VARCHAR w bazie danych. Wydaje się, że wartość nieskończoność zostaje złapany w walidacji JDBC kierowcy, ponieważ otrzymujemy następujące StackTrace gdy próbujesz wstawić Double.Infinity wartość:

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 

Wszelkie pomysły, jak obejść ten problem są mile widziane.

Odpowiedz

1

Oto proste obejście tego problemu: Użyj String dla typu pola i wykonaj konwersję w programach pobierających i ustawiających. W ten sposób nie trzeba zmieniać logiki biznesowej, a faktyczna logika transformacji jest ładnie enkapsulowana.

// 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

Wygląda to na obejście problemu z proppedem. Jedynym ograniczeniem jest to, że ponieważ wartość jest równa VARCHAR w bazie danych, możesz nie być w stanie wykonać obliczeń dla wartości w SQL. – Spaideri