項目中由於需求設計,數據庫中需要一個timestamp時間戳類型的字段來作為區別數據添加和修改的標識。由於timestamp在SQL SERVER 2005數據庫中,不可為空的timestamp類型在語義上等同於binary(8)類型,可為空的 timestamp類型在語義上等同於varbinary(8)類型,這將導致在C#程序中獲取到的timestamp類型則變成了byte[]類型。所以如果我們需要從數據庫中獲取並使用這個時間戳的話就必需經過轉換。
我們先建立一張測試表,語句如下:
CREATE TABLE [dbo].[tb_Ts]( [id] [int] IDENTITY(1,1) NOT NULL, [TS] [timestamp] NULL, [text] [nvarchar](50) NULL ) ON [PRIMARY]
表名為tb_Ts,只有三個字段id,TS和text。其中TS字段就是我們需要的時間戳字段
SQL Server 中timestamp類型的定義
首先看下timestamp在SQL Server 2005中的定義,該定義摘抄自SQL Server 2005聯機叢書(具體詳情點擊此鏈接):
timestamp 公開數據庫中自動生成的唯一二進制數字的數據類型。timestamp 通常用作給表行加版本戳的機制。 存儲大小為 8 個字節。 timestamp 數據類型只是遞增的數字,不保留日期或時間。 若要記錄日期或時間,請使用 datetime 數據類型。
備注:
每個數據庫都有一個計數器,當對數據庫中包含 timestamp 列的表執行插入或更新操作時,該計數器值就會增加。 該計數器是數據庫時間戳。 這可以跟蹤數據庫內的相對時間,而不是時鍾相關聯的實際時間。
一個表只能有一個 timestamp 列, 每次修改或插入包含 timestamp 列的行時,就會在 timestamp 列中插入增量數據庫時間戳值。 這一屬性使 timestamp 列不適合作為鍵使用,尤其是不能作為主鍵使用。
對數據行(row)的任何更新都會更改 timestamp 值,從而更改鍵值。 如果該列屬於主鍵,那么舊的鍵值將無效,進而引用該舊值的外鍵也將不再有效。 如果該表在動態游標中引用,則所有更新均會更改游標中行的位置。 如果該列屬於索引鍵,則對數據行的所有更新還將導致索引更新。
使用某一行中的 timestamp 列可以很容易地確定該行中的任何值自上次讀取以后是否發生了更改。 如果對行進行了更改,就會更新該時間戳值。 如果沒有對行進行更改,則該時間戳值將與以前讀取該行時的時間戳值一致。 若要返回數據庫的當前時間戳值,請使用 @@DBTS。
Transact-SQL timestamp 數據類型不同於在 SQL-2003 標准中定義的 timestamp 數據類型。 SQL-2003 timestamp 數據類型等同於 Transact-SQL datetime 數據類型。
rowversion 的數據類型為 timestamp 數據類型的同義詞,並具有數據類型同義詞的行為。 在 DDL 語句,請盡量使用 rowversion 而不是 timestamp。 有關詳細信息,請參閱 數據類型同義詞 (Transact-SQL)。
程序中獲取出的timestamp
如何使用SQL語句插入timestamp字段值?
我們從上面的timestamp定義中知道了timestamp這個值一般都是數據庫自動添加和修改的,相當於自動增長標識一樣(而且執行update修改語句這個字段也會自動更新),所以一般這個字段我們只做查詢操作。如果要更新這個字段則會提示這個錯誤信息:不能更新時間戳列。但是這個字段是可以手動添加的,不過也只能使用DEFALUT字段(default字段為SQL Service數據庫的一個默認值),如果傳入其他值則會提示錯誤信息:不能將顯式值插入時間戳列。請對列列表使用 INSERT 來排除時間戳列,或將 DEFAULT 插入時間戳列。下面是添加timestamp的SQL語句:
INSERT INTO [tb_Ts]([TS]) VALUES(DEFAULT)
解決數據庫中timestamp類型和C#中byte[]類型轉換問題
在程序中我們發現,通過ADO.NET獲取數據庫中timestamp字段值到程序中,結果類型為byte[]。假設在數據庫中timestamp的值為0x00000000000007D6,那么獲取到.net程序中的值就不是這樣了,一把來說會變成byte[]的數組類型。那么我們的解決方式有兩種,第一種方式是直接在數據庫中將timestamp進行轉換,可以轉換成十六進制字符串類型或者BIGINT的長整形,這也是我推薦的方法。還有一種是在.NET 程序中使用BitConverter方法進行轉換。以下是兩種方式的代碼:
方法一(在SQL中轉換):
SELECT TS ,CAST(TS AS VARBINARY(8)) AS 'timestamp轉十六進制字符串' ,CONVERT(BIGINT,TS) AS 'timestamp轉bigint類型' FROM tb_Ts
這樣一來我們就可以獲取到timestamp的十六進制字符串或者bigint,最終查詢出來的結果如下圖:
另外要說明的一點是,VARBINARY(8)對應的c# 類型是byte[],所以建議直接轉換成bigint類型,否則在C#中還要調用下面的方法
方法二(在程序中轉換,調用下面的方法即可):
/// <summary> /// 將數據庫中timespan轉換成十六進制字符串 /// </summary> /// <param name="objTs">從數據庫中獲取的timespan值</param> /// <returns>timespan十六進制字符串</returns> public string ConvertToTimeSpanString(object objTs) { byte[] btTsArray=objTs as byte[]; string strTimeSpan = "0x"+ BitConverter.ToString(btTsArray).Replace("-",""); return strTimeSpan; }