2011-12-11 12 views
8

ho salvare il mio valore long in una tabella di SQL Server come varbinary(max):SQL Server varbinary bigint con i valori BitConverter.ToInt64 sono diversi

var savedValue = BitConverter.GetBytes(longValue); 

Ora ho bisogno di lavorare con quel valore nella query T-SQL, ma quando Sto cercando di ottenere valore:

select cast(Value as bigint) from dbo.MyValues 

Restituisce un valore numerico diverso. Per esempio se ho salvato -8588797048854775808 in .NET, in T-SQL ottengo 33802181122903688

Per favore dimmi qual è il problema? Hai quel problema qualche soluzione?

+3

perché ti salvare un numero intero a 64 bit come varbinary in primo luogo? – BrokenGlass

+0

In genere si memorizza 'long' in C# come' bigint' in SQL Server. C'è una ragione particolare per cui stai cercando di memorizzare 'long' come' varbinary'? – rsbarro

+0

Poiché questo campo DB non contiene solo valori di tipo int64. – Maybe

risposta

11

La trasmissione da varbinary a bigint (e viceversa) utilizza l'ordine dei byte di rete (big-endian). BitConverter utilizza l'endianità della macchina su cui viene eseguito (little-endian per x86 e x64).

Quindi BitConverter.GetBytes corsa su -8588797048854775808 (0x88CE7696E7167800) è {0x00,0x88,0xE9,0x18,0x69,0x89,0x31,0x77}, e {cast su 0x00,0x88,0xE9,0x18,0x69,0x89,0x31, 0x77} è 0x0088E91869893177 = 38536887891734903.

La cosa ovvia da fare è archiviare gli interi a 64 bit come numeri interi a 64 bit in primo luogo.

Se avete veramente bisogno di fare questa conversione, allora:

var savedValue = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(longValue)) 

cambierà tutto il byte, mentre anche essere portatile che non scambiare i byte se eseguito su un big-endian macchina.

In alternativa, se non si desidera utilizzare lo spazio dei nomi System.Net per qualche motivo, o se si vuole essere estensibile a tipi diversi dai tre IPAddress.HostToNetworkOrder handeles, utilizzare:

var savedValue = BitConverter.GetBytes(longValue); 
if(BitConverter.IsLittleEndian) 
    Array.Reverse(savedValue); 
+0

Grazie per la spiegazione di questo problema. Ma non ho intenzione di salvare di nuovo i valori "lunghi" su "varbinary". Ho solo bisogno di qualche strumento per ottenere valori "bigint" già esistenti in quella colonna come se avessi dei valori all'interno di ".NET BitConverter.ToInt64". Ho bisogno di qualcosa come "Array.Reverse (savedValue);" solo all'interno dell'ambiente di query 'TSQL' – Maybe

+1

Grazie Jon ho trovato! In questo caso ho bisogno di usare la funzione 'reverse' in' TSQL': 'seleziona cast (cast (reverse (Value) come varbinary (max)) come bigint) da dbo.MyValues' – Maybe

+0

Indipendentemente dal design del DB del richiedente , questa domanda mi ha aiutato a risolvere un problema simile quando provavo ad implementare un equivalente C# di una funzione HASHBYTES T-SQL. Non ero nemmeno a conoscenza della possibilità che l'ordine endian fosse diverso. Grazie! –