SQL Server 2008: ошибка вставки FileStream с .NET 3.5SP1 - PullRequest
1 голос
/ 23 марта 2010

Я настроил БД с группой FileStream, и у меня есть таблица с типом файла. При попытке вставить потоковый файл и после создания строки таблицы мой запрос считывает путь к файлу и буфер возвращает нулевой путь к файлу. Я не могу понять, почему, хотя. Вот скрипт создания таблицы:


    /****** Object:  Table [dbo].[JobInstanceFile]    Script Date: 03/22/2010 18:05:36 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[JobInstanceFile](
    [JobInstanceFileId] [int] IDENTITY(1,1) NOT NULL,
    [JobInstanceId] [int] NOT NULL,
    [File] [varbinary](max) FILESTREAM  NULL,
    [FileId] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [Created] [datetime] NOT NULL,
 CONSTRAINT [PK_JobInstanceFile] PRIMARY KEY CLUSTERED 
(
    [JobInstanceFileId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] FILESTREAM_ON [JobInstanceFilesGroup],
UNIQUE NONCLUSTERED 
(
    [FileId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] FILESTREAM_ON [JobInstanceFilesGroup]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[JobInstanceFile] ADD  DEFAULT (newid()) FOR [FileId]
GO

Вот мой процесс, который я вызываю для создания строки перед потоковой передачей файла:


    /****** Object:  StoredProcedure [dbo].[JobInstanceFileCreate]    Script Date: 03/22/2010 18:06:23 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

create proc [dbo].[JobInstanceFileCreate]

    @JobInstanceId int,
    @Created datetime

    as

    insert into JobInstanceFile (JobInstanceId, FileId, Created)
    values (@JobInstanceId, newid(), @Created)

    select scope_identity()
GO

И, наконец, вот код, который я использую:


    public int CreateJobInstanceFile(int jobInstanceId, string filePath)
        {
            using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConsumerMarketingStoreFiles"].ConnectionString))
            using (var fileStream = new FileStream(filePath, FileMode.Open))
            {
                connection.Open();

                var tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);

                try 
                {
                    //create the JobInstanceFile instance
                    var command = new SqlCommand("JobInstanceFileCreate", connection) { Transaction = tran };
                    command.CommandType = CommandType.StoredProcedure;
                    command.Parameters.AddWithValue("@JobInstanceId", jobInstanceId);
                    command.Parameters.AddWithValue("@Created", DateTime.Now);

                    int jobInstanceFileId = Convert.ToInt32(command.ExecuteScalar());

                    //read out the filestream transaction context to stream the file for storage
                    command.CommandText = "select [File].PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() from JobInstanceFile where JobInstanceFileId = @JobInstanceFileId";
                    command.CommandType = CommandType.Text;
                    command.Parameters.AddWithValue("@JobInstanceFileId", jobInstanceFileId);

                    using (SqlDataReader dr = command.ExecuteReader())
                    {
                        dr.Read();

                        //get the file path we're writing out to
                        string writePath = dr.GetString(0);

                        using (var writeStream = new SqlFileStream(writePath, (byte[])dr.GetValue(1), FileAccess.ReadWrite))
                        {
                            //copy from one stream to another
                            byte[] bytes = new byte[65536];
                            int numBytes;
                            while ((numBytes = fileStream.Read(bytes, 0, 65536)) > 0)
                                writeStream.Write(bytes, 0, numBytes);
                        }
                    }

                    tran.Commit();

                    return jobInstanceFileId;
                }
                catch (Exception e)
                {
                    tran.Rollback();
                    throw e;
                }
            }
        }

Может кто-нибудь, пожалуйста, дайте мне знать, что я делаю неправильно. В коде следующее выражение возвращает ноль для пути к файлу и не должно быть:

// получаем путь к файлу, в который мы записываем строка writePath = dr.GetString (0);

Сервер отличается от компьютера, на котором выполняется код, но необходимые общие папки, по-видимому, в порядке, и я также выполнил следующее:

EXEC sp_configure filestream_access_level, 2

Любая помощь будет принята с благодарностью. Спасибо!

1 Ответ

5 голосов
/ 23 марта 2010

Вы не можете открыть SqlFileStream для значения NULL. Измените оператор INSERT, чтобы установить File = 0x, и он должен начать работать.

PS. Некоторые соображения производительности:

  1. Вы можете избежать дополнительной обратной передачи на сервер, выполнив INSERT с предложением OUTPUT , которое возвращает контекст транзакции и путь к файлу вновь вставленного большого двоичного объекта.
  2. Если вы не собираетесь читать из SqlFileStream, откройте его только для записи. В данном конкретном случае это может не иметь большого значения, поскольку открываемый файл пуст. Но если вы обновляете большой файл, то его открытие для ReadWrite приведет к тому, что Sql сначала скопирует весь файл, а только затем позволит вам поиграть с ним.
...