2010-03-17 14 views
5

Supongamos que tengo una columna VarBinary [MAX], ¿puedo insertar o actualizar en esa columna usando un tipo derivado de System.IO.Stream? ¿Cómo?¿Puedo usar una secuencia para INSERTAR o ACTUALIZAR una fila en SQL Server (C#)?

creo que puedo obtener una sólo lectura chorro de una columna de este tipo utilizando un SqlDataReader, llamando GetSqlBytes() en el lector, conseguir la instancia SqlBytes, y luego referencia a la propiedad Stream en eso.

Lo que quiero es lo contrario: quiero un flujo para actualizar o insertar.

¿Posible? (De C# ... Sin escribir T-SQL?)


EDITAR

que he visto código como este:

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; 

... pero no lo sé quiero usar una matriz para especificar el valor. Eso funciona para tamaños de datos pequeños, pero no como los tamaños se hacen más grandes. Quiero escribir en una secuencia.

+0

Ver https://stackoverflow.com/questions/2101149/how-to-i-serialize-alarge-graph-of-net-object-into-a-sql-server-blob-without/2151491# 2151491 para un ejemplo de cómo usar la semántica de transmisión para escribir en un BLOB –

Respuesta

7

Debería poder pasar una instancia de SqlBytes como parámetro a SqlCommand donde sea necesario varbinary. Esa misma clase SqlBytes tiene un constructor overload que envuelve un Stream. Así que simplemente cree una instancia de SqlBytes desde la secuencia, luego pase eso como el valor del parámetro.

En otras palabras, ajustada que en su código revisado, en lugar de esto:

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); 

Utilice esta:

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); 

Por supuesto, no se olvide de disponer el MemoryStream y todos estos otras instancias de IDisposable después de que se haya ejecutado el comando.


Editar

: OK, acabo de ver la parte inferior de su edición, que está dando a entender que los datos es muy grande y no quiero que termine en la memoria, y esto no va a resolver realmente que problema. La cosa es que si el valor es tan grande, es una mala idea almacenarlo en una columna varbinary en primer lugar.

Si está utilizando SQL Server 2008, puede (y debería) usar FILESTREAM en su lugar. Esto realmente hace admite la transmisión "verdadera" en ADO.NET a través de la clase SqlFileStream.

Si no puede usar el almacenamiento FILESTREAM, me temo que tendrá que ocuparse de que los datos estén en la memoria en algún momento, así es como funciona ADO.NET.

+0

Aaron, gracias. ¿Qué pasa con UPDATETEXT? (Consulte http://msdn.microsoft.com/en-us/library/3517w44b.aspx) ¿No puedo usar eso con compensaciones y evitar el problema de tener todos los datos en la memoria al mismo tiempo? Escribiría los datos en pedazos. – Cheeso

+0

@ Cheeso: Parece que Remus ha publicado sobre esto usando 'WRITE', que es similar. Realmente no había pensado en el problema desde ese ángulo; en lugar de intentar pasar una secuencia a ADO.NET como un parámetro en un 'INSERT' o' UPDATE' (que simplemente no se puede hacer), en realidad se ejecuta una semilla 'INSERT' /' UPDATE' y luego varias ' ACTUALIZAR ... ESCRIBIR declaraciones (que agrega, en lugar de reemplaza, los datos de blob). Si está bien con la implementación de declaraciones múltiples, entonces probablemente aceptaría su respuesta. – Aaronaught

1

vladimir-khozeyev señala en su respuesta al How to I serialize a large graph of .NET object into a SQL Server BLOB without creating a large buffer? que todo lo que necesita es un flujo al utilizar .NET Framework 4.5 SqlClient Streaming Support

código SQL:

CREATE TABLE BigFiles 
(
    [BigDataID] [int] IDENTITY(1,1) NOT NULL, 
    [Data] VARBINARY(MAX) NULL 
) 

código C#:

using (FileStream sourceStream = new FileStream(filePath, FileMode.Open)) 
{ 
    using (SqlCommand cmd = new SqlCommand(string.Format("UPDATE BigFiles SET [email protected] WHERE BigDataID = @BigDataID"), _sqlConn)) 
    { 
     cmd.Parameters.AddWithValue("@Data", sourceStream); 
     cmd.Parameters.AddWithValue("@BigDataID", entryId); 

     cmd.ExecuteNonQuery(); 
    } 
} 

Este código funciona en Windows 7, pero no en Windows XP y 2003 Server.

Cuestiones relacionadas