【问题标题】:Can I use a stream to INSERT or UPDATE a row in SQL Server (C#)? [duplicate]我可以使用流在 SQL Server (C#) 中插入或更新一行吗? [复制]
【发布时间】:2011-01-28 10:06:34
【问题描述】:

假设我有一个 VarBinary[MAX] 列,我可以使用派生自 System.IO.Stream 的类型插入或更新该列吗?如何?

我认为我可以使用SqlDataReader 从此类列中获取只读流,在阅读器上调用GetSqlBytes(),获取SqlBytes 实例,然后引用@987654322 @ 属性。

我想要的是相反的 - 我想要一个用于更新或插入的流。

可能吗? (来自c#...不写T-SQL?)


编辑

我见过这样的代码:

    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;  

...但我不想使用数组来指定值。这适用于小数据大小,但不适用于数据变大。我想写入流。

【问题讨论】:

标签: c# .net sql-server stream


【解决方案1】:

vladimir-khozeyev 在他的回答中指出 How to I serialize a large graph of .NET object into a SQL Server BLOB without creating a large buffer? 使用 .NET Framework 4.5 时您只需要一个 Stream SqlClient Streaming Support

SQL 代码:

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

C#代码:

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

        cmd.ExecuteNonQuery();
    }
}

此代码在 Windows 7 上有效,但在 Windows XP 和 2003 Server 上失败。

【讨论】:

    【解决方案2】:

    您应该能够将SqlBytes 的实例作为参数传递给SqlCommand,只要需要varbinary。同样的SqlBytes 类有一个constructor overload,它包装了一个Stream。因此,只需从流中创建一个 SqlBytes 实例,然后将其作为参数值传入。

    换句话说,将其放入修改后的代码中,而不是这样:

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

    使用这个:

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

    当然,不要忘记在命令执行后处置MemoryStream 和所有其他IDisposable 实例。


    编辑:好的,我刚刚看到你的编辑的底部,这意味着数据非常大,你不希望它最终在内存中,这实际上并不能解决这个问题。问题是,如果值那么大,首先将其存储在 varbinary 列中是个坏主意。

    如果您使用的是 SQL Server 2008,则可以(并且应该!)改用 FILESTREAM。这实际上确实通过SqlFileStream 类支持ADO.NET 中的“真实”流。

    如果您不能使用FILESTREAM 存储,那么恐怕您将不得不在某个时间点处理内存中的数据,这就是 ADO.NET 的工作原理。

    【讨论】:

    • 亚伦,谢谢。更新文本呢? (请参阅msdn.microsoft.com/en-us/library/3517w44b.aspx)我不能将它与偏移一起使用并避免一次将所有数据都保存在内存中的问题吗?我会分块写入数据。
    • @Cheeso:看起来 Remus 使用 WRITE 发布了有关此问题的信息,类似。我并没有真正从那个角度考虑过这个问题。而不是尝试将流作为INSERTUPDATE 中的参数传递给ADO.NET(这根本无法完成),您实际上执行了一个种子INSERT/UPDATE,然后是几个连续的@ 987654343@ 语句(附加而不是替换 blob 数据)。如果您对多语句实现感到满意,那么我可能会接受他的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 2014-08-01
    • 2020-10-17
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多