忙了好长一阵子,silvelight项目总算告一段落了,在这个项目中,使用了sqlserver 2008,当然是觊觎它的新特性fileStream和hierarchyid.因此在最开始,没少去查阅msdn和做一些练习,所以元旦长假就打算做一个比较完整的练习,从安装sqlserver2008开始,在msdn的帮助下一步一步来完成.下面是完成fileStream练习的步骤:
1.SQL Server2008 enabled fileStream
因为我在安装sql server 2008的时候,在配置filestream的时候就已经将sql server2008的选项打勾了。当然如果安装的时候没有选择enabled fileStream,可以在
sql server configuration manager(配置管理器)如图,或者在查询分析器里面执行下面的sql 语句
EXEC sp_configure filestream_access_level, 2 RECONFIGURE ;filestream_access_level 的值 详细参考msdn
2.Database enabled fileStream
下面是我的data base script,显然这里和一般的数据库多了一个'Group'(fileStream Data类型)
CREATE DATABASE [fileStreamTest] ON PRIMARY
( NAME = N'fileStreamTest', FILENAME = N'C:\data\fileStreamTest.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
FILEGROUP [fileStreamGroup1] CONTAINS FILESTREAM DEFAULT
( NAME = N'fileStreamGroup', FILENAME = N'C:\data\fileStreamGroup' )
LOG ON
( NAME = N'fileStreamTest_log', FILENAME = N'C:\data\fileStreamTest_log.ldf' , SIZE = 1024KB , MAXSIZE = 1GB , FILEGROWTH = 10%)
GO
注意的地方是:c:\Data 目录必须存在,而filestream1'子目录在c:\Data则不能已存在
执行完毕查看c:\Data目录下面有fileStream1目录,打开发现有 有一个filestream.hdr f文件和一个名为 $FSLOG 的字文件夹.
3.Table enabled FileStream
在这里问题就来了(问题先不说),我按照 How to: Create a Table for Storing FILESTREAM Data这里讲的新建Records,脚本如下,按照msdn说明,Id列是一个ROWGUIDCOL列,Chart 作为文件存储的列不仅是VARBINARY(MAX)类型 ,同时还需要赋予一个fileStream特性.
CREATE TABLE .dbo.Records
(
[Id] [uniqueidentifier] ROWGUIDCOL NOT NULL UNIQUE,
[SerialNumber] INTEGER UNIQUE,
[Chart] VARBINARY(MAX) FILESTREAM NULL
)
4.通过ado.net来访问fileStream,我参考项目中用到的方法写了这个方法
2 {
3 SqlConnection conn = null ;
4 SqlTransaction tran = null ;
5 SqlCommand cmd = null ;
6 try
7 {
8 // get file content
9 FileStream input = new FileStream(fileName, FileMode.Open, FileAccess.Read);
10 byte [] buffer = new byte [( int )input.Length];
11 input.Read(buffer, 0 , buffer.Length);
12
13 conn = GetConnection();
14 tran = conn.BeginTransaction();
15 // call proc
16 cmd = new SqlCommand( " putFileStream " , conn, tran); // add a new record ,but filestream is null,return filestream.PathName
17 cmd.CommandType = System.Data.CommandType.StoredProcedure;
18 cmd.Parameters.Add( new SqlParameter( " @serialNumber " , new Random().Next( 1000 )));
19 SqlDataReader r = cmd.ExecuteReader(System.Data.CommandBehavior.SingleRow);
20 r.Read();
21 string id = r[ 0 ].ToString();
22 string path = r[ 1 ].ToString();
23 r.Close();
24
25 // get the transaction context
26 SqlCommand command = new SqlCommand( @" select Chart.PathName(),GET_FILESTREAM_TRANSACTION_CONTEXT() from Records where id=@id " , conn, tran);
27 command.Parameters.AddWithValue( " @id " , id);
28 // open a Filestream to write the blob
29 SqlDataReader reader;
30 reader = command.ExecuteReader(CommandBehavior.SingleRow);
31 reader.Read();
32 SqlString sqlFilePath = reader.GetSqlString( 0 );
33 SqlBinary transactionToken = reader.GetSqlBinary( 1 );
34
35 reader.Close();
36
37 if (transactionToken.Length != 0 )
38 {
39 // open a sqlfileStream
40 SqlFileStream stream = new SqlFileStream(sqlFilePath.Value, transactionToken.Value, FileAccess.Write, FileOptions.SequentialScan, 0 );
41 // write file to sqlfilestream
42 stream.Write(buffer, 0 , buffer.Length);
43 stream.Close();
44 }
45 tran.Commit();
46 conn.Close();
47 }
48 catch
49 {
50
51 }
52 }
我开始调用put方法,可结果数据库没有记录,这让我很好奇,我开启了sql profile并同时开始debug,发现都正常,可结果数据库没有记录,我把sqlprofile抓到的
sql exec putFileStream @serialNumber=555,拿到分析器查询,没有问题,不过当我用sql加入了一条记录之后,在用程序调用put方法结果就正常了,不知道什么原因总之郁闷了几个小时。
下面也贴一下读取fileStream的代码
2 {
3 SqlConnection conn = null;
4 SqlTransaction tran = null;
5 SqlCommand cmd = null;
6 byte[] bytes = null;// getFileStream
7 conn = GetConnection();
8 tran = conn.BeginTransaction();
9
10 cmd = new SqlCommand("SELECT [Chart].PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() FROM [Records] WHERE [id] = @id;", conn, tran);
11 //cmd.CommandType = System.Data.CommandType.StoredProcedure;
12 cmd.Parameters.Add("@id", SqlDbType.UniqueIdentifier).Value = id;
13
14 SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.SingleRow);
15 if (rdr.Read())
16 {
17 SqlString sqlFilePath = rdr.GetSqlString(0);
18 SqlBinary transactionToken = rdr.GetSqlBinary(1);
19 rdr.Close();
20
21 SqlFileStream fileStream = new SqlFileStream(sqlFilePath.Value, transactionToken.Value, FileAccess.Read);
22 bytes = new byte[fileStream.Length];
23 fileStream.Read(bytes, 0, bytes.Length);
24 fileStream.Close();//if fileStream have not close,tran.Commit throw process error
25 tran.Commit();
26 }
27 conn.Close();
28 return bytes;
29 }
30
31
参考文档http://technet.microsoft.com/en-us/library/cc645923.aspx