Class' System.DBNull'无法编入索引,因为它没有默认属性

时间:2016-11-08 12:14:16

标签: vb.net

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        cn.Open()
        Dim arrimage() As Byte
        Dim ms As New MemoryStream()
        If (pb1.Image IsNot Nothing) Then
            pb1.Image.Save(ms, pb1.Image.RawFormat)
            arrimage = ms.GetBuffer
            ms.Close()
        End If
        With cmd
            .Connection = cn
            .CommandText = "INSERT INTO [Example]([PName],[Pic])VALUES(@a2,@a1)"
            .Parameters.Add("a0", OleDbType.VarChar).Value = tName.Text
            .Parameters.Add("a1", OleDbType.Binary).Value = IIf(pb1.Image IsNot Nothing, arrimage, DBNull.Value())
            .Dispose()
            .ExecuteNonQuery()
        End With
        cn.Close()
    End Sub

1 个答案:

答案 0 :(得分:1)

您的代码中存在多个问题。按顺序出现:

不要使用GetBuffer()

MSDN所述,缓冲区的大小可以是流中数据的两倍。这将使用额外的空值不必要地膨胀数据库。请改用ToArray()

由于数据库中的图像必须与字节数组进行转换,因此请考虑将图像存档到文件夹并仅将名称存储在数据库中。然后,您可以预先添加存档文件夹名称以快速加载图像。

而不是 RawFormat ,我会将其编码为类似JPEG的内容。

使用Using

通常需要处理任何具有.Dispose方法的东西。这将适用于OleDBCommand对象(MemStream确实不需要处理,但这是一个实现细节)。

Using阻止DimNewDispose加入一个方便易用的区块:

Using foo As New FooBar()
   ...
End Using

第一行声明一个foo变量,并创建一个FooBar的实例,您可以在该块中使用它。最后,它会自动处理。

不要使用全局DBCommand对象

您的代码未显示正在声明或创建的cmd,因此它必须是表单级对象。 不要这样做。除非您的所有应用程序都是一回事,否则对DBCommand对象没有任何可重用性。

在代码中添加2个参数。下次你去使用它时,它仍然可以有那些2,代码将增加2个,这比SQL查询所需的更多。在这种情况下,代码处理它,但 表示下次引用它时,您将得到ObjectDisposedException

  • 如上所述,您的代码在 Dispose之前调用ExecuteNonQuery 会崩溃 - 您无法使用已处置的对象。

DBNull.Value不是方法

至于编译器错误,你有这个:

IIf(pb1.Image IsNot Nothing, arrimage, DBNull.Value())

DBNull.Value是一个属性,而不是一个方法,所以不需要parens。此外,你应该使用" new" If运算符而非旧IIF函数。运算符被短路,因此忽略不适用的part /子句:

' should evaluate the data (arrimage) not its source
If(pb1.Image IsNot Nothing, arrimage, DBNull.Value)   ' no parens

修改后的代码:

cn.Open()
Dim arrimage() As Byte = Nothing

If (pb.Image IsNot Nothing) Then
    Using ms As New MemoryStream()
        pb.Image.Save(ms, ImageFormat.Jpeg)
        arrimage = ms.ToArray()
    End Using
End If

Dim sql = "INSERT INTO [Example]([PName],[Pic]) VALUES (@a2,@a1)"

Using cmd As New OleDbCommand(sql, cn)
    cmd.Parameters.Add("a0", OleDbType.VarChar).Value = tName.Text
    If arrimage IsNot Nothing Then
        cmd.Parameters.Add("a1", OleDbType.VarBinary).Value = arrimage 
    Else
        cmd.Parameters.Add("a1", OleDbType.VarBinary).Value = DBNull.Value
    End If
    cmd.ExecuteNonQuery()
End Using

cn.Close()
  • 由于命令对象没有查询和连接都没用,我更喜欢在构造函数中传递它们。它使代码更短,并确保它具有所需的功能
  • 每次都应该创建,使用和处理连接
  • 创建一个方便的扩展方法,将图像转换为字节数组
  • 也很容易