【问题标题】:Storing an image into an Attachment field in an Access database将图像存储到 Access 数据库的附件字段中
【发布时间】:2013-09-12 12:29:18
【问题描述】:

我正在编写一个需要在数据库中存储图像的 VB 应用程序。用户在他们的计算机上选择图像,这将路径作为字符串提供给我。这是我的尝试,但是我收到错误“INSERT INTO 查询不能包含多值字段。”

这是我的代码:

Dim buff As Byte() = Nothing
Public Function ReadByteArrayFromFile(ByVal fileName As String) As Byte()
    Dim fs As New FileStream(fileName, FileMode.Open, FileAccess.Read)
    Dim br As New BinaryReader(fs)
    Dim numBytes As Long = New FileInfo(fileName).Length
    buff = br.ReadBytes(CInt(numBytes))
    Return buff
End Function

Sub ....
    Dim connImg As New OleDbConnection
    Dim sConnString As String
    Dim cmdImg As New OleDbCommand

    sConnString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & My.Settings.DB & ";Persist Security Info=False;"
    connImg = New OleDbConnection(sConnString)
    connImg.Open()
    cmdImg.Connection = connImg
    cmdImg.CommandType = CommandType.Text

    If d.slogo <> "" Then
        cmdImg.CommandText = "INSERT INTO Logo ( refId, [type], [img] ) VALUES(@refId, @type, @imgBinary)"
        cmdImg.Parameters.Add("@refId", OleDbType.Double).Value = refId
        cmdImg.Parameters.Add("@type", OleDbType.Double).Value = 0
        cmdImg.Parameters.Add("@imgBinary", OleDbType.VarBinary).Value = ReadByteArrayFromFile(PathToImage)
        cmdImg.ExecuteNonQuery()
    End If
    ....
End Sub

我已经尝试在网上搜索其他解决方案,但我找到的似乎都是 VB6 或 VBA 代码。而且我知道人们会争辩说图像不应该存储在数据库中,但在这种情况下,这是我唯一的选择。

感谢您的帮助!

【问题讨论】:

  • 您介意分享您的表和任何相关表的架构吗?
  • 对不起,我不能 100% 确定您在寻找什么,但我会尽力而为:在这个 Logo 表中,有 3 个字段。 refId 并键入“数字”。 img 作为“附件”。 refId 只是一个 ID,它链接到另一个表中的 productId。每个产品都会附有不同的图片(想想杂志中的广告和封面图片)。现在只有2个,但以后会增加。 refId 和 type 组合为主键。
  • 您遇到的问题是 refID 而不是图像。我已经有一段时间没有进行 Access 开发了,但我进行了一些谷歌搜索,并且有一些方法可以绕过这个多值列。
  • 如果我在没有 img 字段的情况下运行查询,它工作正常。我不认为这是 refID。

标签: database vb.net attachment oledbcommand ms-access-2013


【解决方案1】:

正如您所发现的,您不能使用 SQL 语句将文件插入到 Access 数据库中的 Attachment 字段中。您必须使用 ACE DAO Field2 对象的 LoadFromFile() 方法。以下 C# 代码适用于我。它改编自 Office 博客条目here

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Access.Dao;

namespace daoConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // This code requires the following COM reference in your project:
            //
            // Microsoft Office 14.0 Access Database Engine Object Library
            //
            var dbe = new DBEngine();
            Database db = dbe.OpenDatabase(@"C:\__tmp\testData.accdb");
            try
            {
                Recordset rstMain = db.OpenRecordset(
                        "SELECT refId, img FROM Logo WHERE refId = 1", 
                        RecordsetTypeEnum.dbOpenDynaset);
                if (rstMain.EOF)
                {
                    // record does not already exist in [Logo] table, so add it
                    rstMain.AddNew();
                    rstMain.Fields["refId"].Value = 1;
                }
                else
                {
                    rstMain.Edit();
                }
                // retrieve Recordset2 object for (potentially multi-valued) [img] field
                //     of the current record in rstMain
                Recordset2 rstAttach = rstMain.Fields["img"].Value;
                rstAttach.AddNew();
                Field2 fldAttach = 
                        (Field2)rstAttach.Fields["FileData"];
                fldAttach.LoadFromFile(@"C:\__tmp\testImage.jpg");
                rstAttach.Update();
                rstAttach.Close();
                rstMain.Update();
                rstMain.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    我根据上面的代码和来自here 的博客条目做了同样的事情。

    这是我的 vb.net 代码,它允许我执行 OpenFileDialog 和多项选择,并且该函数可以很好地处理存储多个文件。尽管我确实必须为 Microsoft Office 15.0 Access 数据库引擎对象库添加对我的项目的引用才能使其正常工作。我认为您也可以降到 12.0 或 14.0。

    Private Sub AddAttachment(ByVal Files() As String)
        Const Caller = "AddAttachment"
        Dim dbe = New Microsoft.Office.Interop.Access.Dao.DBEngine()
        Dim db As Microsoft.Office.Interop.Access.Dao.Database
        db = dbe.OpenDatabase(dbPath)
        Try
            Dim rstMain As Microsoft.Office.Interop.Access.Dao.Recordset
            rstMain = db.OpenRecordset("SELECT ID, fieldName FROM tableName WHERE ID = " + (dt.Rows(currentRow).Item("ID").ToString), Microsoft.Office.Interop.Access.Dao.RecordsetTypeEnum.dbOpenDynaset)
            If (rstMain.EOF) Then
                rstMain.AddNew()
                rstMain.Fields("ID").Value = 1
            Else
                For Each value As String In Files
                    rstMain.Edit()
                    Dim rstAttach As Microsoft.Office.Interop.Access.Dao.Recordset2
                    rstAttach = rstMain.Fields("ATTACHMENTS").Value
                    rstAttach.AddNew()
                    Dim fldAttach As Microsoft.Office.Interop.Access.Dao.Field2
                    fldAttach = rstAttach.Fields("FileData")
                    fldAttach.LoadFromFile(value)
                    rstAttach.Update()
                    rstAttach.Close()
                Next
                rstMain.Update()
                rstMain.Close()
            End If
    
        Catch ex As Exception
            If Err.Number <> 3820 Then
                MsgBox(ex.Message)
            Else
                MsgBox("File of same name already attached", MsgBoxStyle.Critical, "Cannot attach file" & Caller)
                MessageBox.Show(ex.Message)
            End If
    
        End Try
    End Sub
    

    我现在正在处理 RemoveAttachments 和保存附件字段中的文件的功能。我稍后会在这里发布这些。

    【讨论】:

      【解决方案3】:

      还有一点要补充的。如果您的数据库是加密的,那么您将需要添加到 OpenDatabase 命令。

      这是我在 C# 中使用的代码,但 VB.NET 代码将非常相似。 db = dbe.OpenDatabase(dbPath, false, false,"MS Access;PWD=password");

      我花了很长时间才尝试自己追踪这个问题,我将尝试分解该方法的各个部分。可以找到它的 MSDN 文章here

      第一个参数:dbPath,与原帖中的用法相同。您要打开的数据库的位置和文件名。

      第二个参数:错误。这是一个真/假参数,如果为真,则以独占模式打开数据库。这样只有这个单一的程序可以使用它。大多数时候这应该是错误的。仅在必要时使用独占模式。

      第三个参数:错误。这是另一个真/假论点。这一次,如果它是真的,那么它将以只读模式打开数据库。这意味着您只能使用记录集来读取信息,而不能使用编辑、添加或删除方法。根据您的需要,这可以是真或假。

      第四个参数:这设置了如何打开数据库的特定属性。在这种情况下。它说将 Microsoft Access 属性“PWD”设置为“密码”。在此属性设置中,将告诉方法使用密码“密码”打开加密数据库。当然,您需要将“密码”更改为要打开数据库的实际密码,但我一直在寻找这个。

      我希望这会有所帮助。

      【讨论】:

      • 能否请您详细说明您的答案,添加更多关于您提供的解决方案的描述?
      猜你喜欢
      • 2013-06-11
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 2012-06-04
      • 2014-11-09
      • 1970-01-01
      相关资源
      最近更新 更多