2016-06-15 6 views
0

私はFileForUploadingクラスをデータベースにアップロードする必要があります。データベースへのストリームのアップロード

public class FileForUploading 
{ 
    public FileForUploading(string filename, Stream stream) 
    { 
     this.Filename = filename; 
     this.Stream = stream; 
    } 

    public string Filename { get; private set; } 

    public Stream Stream { get; private set; } 
} 

しかし私は、唯一のFilenameプロパティが含まれている非常に単純なクラスですFileForUploadingEntity に変換するエンティティフレームワークを使用しています。 Streamをメモリに保存するのではなく、直接データベースにアップロードします。

Streamを直接データベースに「ストリーム」するにはどうすればよいでしょうか?

これまでのところ、私はこの

private void UploadStream(string name, Stream stream) 
    { 
     var sqlQuery = @"UPDATE dbo.FilesForUpload SET Content [email protected] WHERE [email protected];"; 

     var nameParameter = new SqlParameter() 
     { 
      ParameterName = "@name", 
      Value = name 
     }; 

     var contentParameter = new SqlParameter() 
     { 
      ParameterName = "@content", 
      Value = ConvertStream(stream), 
      SqlDbType = SqlDbType.Binary 
     }; 

     // the database context used throughout the application. 
     this.context.Database.ExecuteSqlCommand(sqlQuery, contentParameter, nameParameter); 
    } 

を思い付くそしてここbyte[]Streamを変換し、私のConvertStreamでいます。 (データベース内のvarbinary(MAX)として格納されている。

private static byte[] ConvertStream(Stream stream) 
    { 
     using (var memoryStream = new MemoryStream()) 
     { 
      stream.CopyTo(memoryStream); 
      return memoryStream.ToArray(); 
     } 
    } 

が十分に上記の溶液は良いですか?Streamが大きい場合、それは私がストリームを保存したくない?

+0

上記のソリューションでは、最初に言及したアプリケーションのメモリ内のストリームの内容が、まだ回避しようとしていたものであることを提案しました。 「私はストリームをメモリに保存するのではなく、直接データベースにアップロードしたい」 – Igor

+0

これがなぜそうであるかについてもう少し具体的にできますか?だから私は何を変えなければならないかを知っている。 – pgerchev

+0

AFAIK、あなたはストリーミング 'INSERT'だけをストリーミング' UPDATE'することはできません。 SQLBulkCopy()はこれを行うための1つの方法です。 – RBarryYoung

答えて

2

も行います

上記の解決策では、あなたが最初に言いましたアプリケーションのメモリ内のストリームの内容がまだ試していたものであることを提案しました避けるために。

EFを使い、ストリームをアップロードするにはasync関数を使用するのが一番の方法です。次の例はMSDN article SqlClient Streaming Supportです。

// Application transferring a large BLOB to SQL Server in .Net 4.5 
private static async Task StreamBLOBToServer() { 

using (SqlConnection conn = new SqlConnection(connectionString)) { 
    await conn.OpenAsync(); 
    using (SqlCommand cmd = new SqlCommand("INSERT INTO [BinaryStreams] (bindata) VALUES (@bindata)", conn)) { 
     using (FileStream file = File.Open("binarydata.bin", FileMode.Open)) { 

      // Add a parameter which uses the FileStream we just opened 
      // Size is set to -1 to indicate "MAX" 
      cmd.Parameters.Add("@bindata", SqlDbType.Binary, -1).Value = file; 

      // Send the data to the server asynchronously 
      await cmd.ExecuteNonQueryAsync(); 
     } 
    } 
} 
} 

このサンプルを次のように変換して問題なく動作させることができます。メソッドのシグネチャを変更して非同期にすることで、長期間のデータベース更新中にスレッドがブロックされないようにすることができます。

// change your signature to async so the thread can be released during the database update/insert act 
private async Task UploadStreamAsync(string name, Stream stream) { 

    var conn = this.context.Database.Connection; // SqlConnection from your DbContext 
    if(conn.State != ConnectionState.Open) 
     await conn.OpenAsync(); 
    using (SqlCommand cmd = new SqlCommand("UPDATE dbo.FilesForUpload SET Content [email protected] WHERE [email protected];", conn)) { 
      cmd.Parameters.Add(new SqlParameter(){ParameterName = "@name",Value = name}); 
      // Size is set to -1 to indicate "MAX" 
      cmd.Parameters.Add("@content", SqlDbType.Binary, -1).Value = stream; 
      // Send the data to the server asynchronously 
      await cmd.ExecuteNonQueryAsync(); 
    } 
} 

つ以上のノート。大規模な非構造化データセット(アップロードするストリーム)を保存する場合は、データベースに保存しない方が良いでしょう。リレーショナルデータベースは実際にはこのことを念頭に置いて設計されておらず、データを扱うのが煩わしく、データベーススペースを本当に速く掘り下げて、他の操作をより困難にする(バックアップ、リストアなど)理由は数多くあります。 )。

ポインタはレコードに保存できますが、実際の構造化されていないデータはディスクに保存されています。これはSql Server FileStreamを使用して行うことができます。 ADO.NETでは、SqlFileStreamで作業します。ここでは、Sqlファイルストリームを使用できるようにSqlサーバーとデータベースを構成する方法について説明します。また、SqlFileStreamクラスの使用方法に関するいくつかのVB.netの例もあります。

An Introduction to SQL Server FileStream


私はあなたのデータリポジトリとしてMicrosoft SQL Serverを使用していたと仮定しました。この前提が正しくない場合は、質問を更新し、接続先の正しいデータベースサービスのタグを追加してください。

+0

これはクライアントプログラム内でストリーミングしていますが、SQL Server側ではストリーミングされませんが、SQLコマンドの増分実行に依存するため、かなり遅くなります。 'SQLBulkCopy()'は大規模なデータセットのための好ましいアプローチの一つであり、典型的には10倍から100倍高速です。 – RBarryYoung

関連する問題