views:

82

answers:

2

Suppose I have a VarBinary[MAX] column, can I insert or update into that column using a type derived from System.IO.Stream? How?

I think that I can obtain a read-only stream from such a column using a SqlDataReader, calling GetSqlBytes() on the reader, getting the SqlBytes instance, and then referencing the Stream property on that.

What I want is the converse - I want a stream for update or insert.

Possible? (from c#... Without writing T-SQL ?)


EDIT

I've seen code like this:

    System.Data.SqlClient.SqlCommand _SqlCommand
        = new System.Data.SqlClient.SqlCommand(_SQL, _SqlConnection);

    // Convert image to memory stream
    System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream();
    _Image.Save(_MemoryStream, _ImageFormat);

    // Add image as SQL parameter
    System.Data.SqlClient.SqlParameter _SqlParameter 
        = new System.Data.SqlClient.SqlParameter("@" + _ImageFieldName, SqlDbType.Image);

    _SqlParameter.Value = _MemoryStream.ToArray();
    _SqlCommand.Parameters.Add(_SqlParameter);

    // Executes a Transact-SQL statement against the connection 
    // and returns the number of rows affected.
    _SqlRetVal = _SqlCommand.ExecuteNonQuery();

    // Dispose command
    _SqlCommand.Dispose();
    _SqlCommand = null;  

...but I don't want to use an array to specify the value. That works for small data sizes, but not as sizes get larger. I want to write into a stream.

+1  A: 

You should be able to pass an instance of SqlBytes as a parameter to a SqlCommand wherever a varbinary is needed. That same SqlBytes class has a constructor overload that wraps a Stream. So simply create a SqlBytes instance from the stream, then pass that in as the parameter value.

In other words, fitting that into your revised code, instead of this:

MemoryStream _MemoryStream = new System.IO.MemoryStream();
_Image.Save(_MemoryStream, _ImageFormat);
SqlParameter _SqlParameter = new 
    SqlParameter("@" + _ImageFieldName, SqlDbType.Image);
_SqlParameter.Value = _MemoryStream.ToArray();
_SqlCommand.Parameters.Add(_SqlParameter);

Use this:

MemoryStream _MemoryStream = new System.IO.MemoryStream();
_Image.Save(_MemoryStream, _ImageFormat);
_MemoryStream.Position = 0;  // I *think* you need this
SqlParameter _SqlParameter = new 
    SqlParameter("@" + _ImageFieldName, SqlDbType.VarBinary);
_SqlParameter.Value = new SqlBytes(_MemoryStream);
_SqlCommand.Parameters.Add(_SqlParameter);

Of course, don't forget to dispose the MemoryStream and all these other IDisposable instances after the command has been executed.


Edit: OK, I just saw the bottom of your edit, which is implying that the data is extremely large and you don't want it to end up in memory, and this won't actually solve that problem. Thing is, if the value is that big, it's a bad idea to be storing it in a varbinary column in the first place.

If you're using SQL Server 2008, you can (and should!) use FILESTREAM instead. This actually does support "true" streaming in ADO.NET through the SqlFileStream class.

If you can't use FILESTREAM storage, then I'm afraid you're going to have to deal with the data being in memory at some point in time, that's pretty much how ADO.NET works.

Aaronaught
Aaron, thanks. What about UPDATETEXT? (See http://msdn.microsoft.com/en-us/library/3517w44b.aspx) Can't I use that with offsets and avoid the problem of having all the data in memory at one time? I would write the data in chunks.
Cheeso
@Cheeso: Looks like Remus has posted about this using `WRITE`, which is similar. I hadn't really thought about the problem from that angle; instead of trying to pass a stream to ADO.NET as a parameter in one `INSERT` or `UPDATE` (which simply can't be done), you actually execute a seed `INSERT`/`UPDATE` and then several successive `UPDATE...WRITE` statements (which appends, rather than replaces, the blob data). If you're OK with the multi-statement implementation then I would probably accept his answer.
Aaronaught
+1  A: 

See http://stackoverflow.com/questions/2101149/how-to-i-serialize-a-large-graph-of-net-object-into-a-sql-server-blob-without/2151491#2151491 for an example how to use streaming semantics to write into a BLOB

Remus Rusanu