如何将图片存储到 varbinary(max) 列中?

8

在将图像插入到SQL Server 2008中时,我遇到了以下SQL异常。

不允许从数据类型nvarchar隐式转换为varbinary(max)。使用CONVERT函数运行此查询

在数据库中,Image列的数据类型是Varbinary(MAX)。

编辑

代码从评论中提取

paramaters.Add(getParam("@imageFilePath", DbType.AnsiString, imageFilePath));

你是在插入base64表示或其他什么吗?听起来你使用的SqlParameter对象配置不正确。 - Tejs
4个回答

15

使用此方法将文件读入字节数组:

    // Old fashioned way
    public static byte[] ReadFile(string filePath)
    {
        byte[] buffer;
        FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        try
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
                sum += count;  // sum is a buffer offset for next reading
        }
        finally
        {
            fileStream.Close();
        }
        return buffer;
    }
或者
    // Thanks Magnus!
    byte[] data = System.IO.File.ReadAllBytes(filePath);

接着使用以下代码保存图像数据(我正在使用名为 "instance" 的图像类,其中包含我的图像信息和字节数组在 instance.Data 中):

   using(SqlCommand cm = new SqlCommand("SaveImage", connection, transaction)){
       cm.CommandType = CommandType.StoredProcedure;
       cm.Parameters.Add(new SqlParameter("@Id", SqlDbType.Int,0, ParameterDirection.InputOutput, false, 10, 0, "Id", DataRowVersion.Current, (SqlInt32)instance.Id));
       cm.Parameters.Add(new SqlParameter("@Title", SqlDbType.NVarChar,50, ParameterDirection.Input, false, 0, 0, "Title", DataRowVersion.Current, (SqlString)instance.Title));
       if (instance.Data.Length > 0)
       {
           cm.Parameters.Add(new SqlParameter("@Data", SqlDbType.VarBinary,instance.Data.Length, ParameterDirection.Input, false, 0, 0, "Data", DataRowVersion.Current, (SqlBinary)instance.Data));
       }
       else
       {
           cm.Parameters.Add(new SqlParameter("@Data", SqlDbType.VarBinary,0, ParameterDirection.Input, false, 0, 0, "Data", DataRowVersion.Current, DBNull.Value));                    
       }

       cm.ExecuteNonQuery();
   )

这里是一个存储过程的示例:

CREATE PROCEDURE SaveImage
(
@Id int OUTPUT 
,@Title nvarchar(50)
,@Data varbinary(MAX)
)
AS
SET NOCOUNT ON
SET XACT_ABORT ON

IF @Id IS NULL OR @Id <= 0
BEGIN
SELECT @Id = ISNULL(MAX([Id]),0) + 1 FROM [dbo].[Images]
END

INSERT INTO [dbo].[Images] (
[Id]
,[Title]
,[Data]
) VALUES (
@Id
,@Title
,@Data
)

10
System.IO.File.ReadAllBytes(filePath) - Magnus
你应该在 Parameters.Add 行中将 "instance.Data.Length" 替换为 "-1",以表示 VARBINARY(MAX)。 - Mark Lakata
@MarkLakata,如果是varbinary(max)字段,是否有情况下传递实际数据长度不起作用?或者您是建议这样做作为最佳实践?请支持您的答案(为了我的学习)。谢谢! - Bahri Gungor
我建议将其作为最佳实践,使代码更具可重用性。现有的代码也可以正常工作。 - Mark Lakata
1
+1 谢谢,但你本可以简化一下让它更易于理解。例如:https://dev59.com/uXNA5IYBdhLWcg3wKam3#1088630 - Sam

5
您之所以会收到错误提示,是因为您试图将文本插入到varbinary(max)列中,因此不是存储图像而是存储图像的地址。如果您只想存储路径,请将列类型从varbinary(max)更改为varchar(max)。如果您确实想存储图像字节,则需要编写代码将图像作为字节数组从文件中读取,然后像这样插入数据:
byte [] buffer = File.ReadAllBytes("Path/to/your/image/");
...

SqlCommand command = ....
command.CommandType=CommandType.StoredProcedure;
command.Parameters.AddWithValue("@image",buffer);
command.ExecuteNonQuery();

或者

SqlCommand command = ....
command.Text="INSERT INTO YOUR_TABLE_NAME (image) values (@image)";
command.Parameters.AddWithValue("@image",buffer);
command.ExecuteNonQuery();

2

看起来你正在尝试将图像数据设置到一个被设置为NVARCHAR(基本文本)数据类型的列中。要么将图像数据设置到正确的VARBINARY(MAX)列中--或者如果该列尚不存在,则将其添加到您的表中。或者,如果确实是正确的列,并且最初创建时只是使用了错误的数据类型,那么可以通过ALTER TABLE命令将当前使用的列更改为VARBINARY(MAX)数据类型。


嗨,Mufasa,以下是我认为有问题的add方法,我正在遇到什么是dbType,我需要更改。请帮帮我。 paramaters.Add(getParam("@imageFilePath", DbType.AnsiString, imageFilePath)); - Indra
不行 - 你需要做更多的事情而不仅仅是改变类型。你不能只是将文件路径发送给SQL Server,你需要发送二进制数据。 - Martin Smith
我是新手,我该怎么做? - Indra
虽然stackoverflow.com上已经有很多答案了,但我仍不确定最佳的方法是什么。 - Martin Smith
我是指更改在数据库中存储的数据类型。SQL Server Management Studio显示该字段的数据类型是什么?你想保持这种方式吗?你设计了这个数据库,还是它已经有数据了?你应该存储数据本身(二进制数据),还是应该将图像保存到服务器,然后将文件路径存储在数据库字段中? - Jon Adams

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接