【问题标题】:Saving OLE Objects in Access field with VBA使用 VBA 在 Access 字段中保存 OLE 对象
【发布时间】:2018-07-20 10:15:56
【问题描述】:

我知道这个主题已经被广泛覆盖,但我无法找到解决我的特定问题的方法。

我有一个表,其中有一列 附件 是 OLE 对象数据类型。表的后端是 SQL Server 表,Attachments 列的数据类型为 VARBINARY(MAX)。

如果我右键单击 Access 中的 Attachments 字段,会弹出一个菜单,其中包含 Insert Object... 的选项字段中的文件。

以这种方式插入的文件只需双击该字段即可打开以进行查看和编辑。

现在。我需要使用 VBA 做同样的事情。我需要获取文件列表并将它们插入到相应行的 Attachments 字段中。这应该不是一项艰巨的任务,因为众所周知如何使用 ADODB.Stream 在字段中插入文件。下面是一个简单的代码来试试这个概念:

Private Sub POC()

    Dim db As DAO.Database
    Dim rsa As DAO.Recordset
    Dim stream As ADODB.stream

    Set db = CurrentDb()
    Set rsa = db.OpenRecordset("ZipCodeAttachments", dbOpenDynaset, dbSeeChanges)

    rsa.MoveFirst
    rsa.MoveNext

    rsa.Edit

    Set stream = New ADODB.stream
    stream.Type = adTypeBinary
    stream.Open
    stream.LoadFromFile Application.CurrentProject.Path & "\Attachments\537.zip"

    rsa.Fields("Attachments").value = stream.Read

    rsa.Update
    rsa.Close

    Set rsa = Nothing
    Set dba = Nothing
End Sub

代码在第二行的Attachments 字段中插入一个文件。我可以验证该值已通过 SSMS 添加。但是,当我尝试像之前对第一行所做的那样打开该字段进行查看和编辑时,这次我收到了一个错误:

显然,使用 VBA 保存文件的方式有问题。

我做错了什么?如何使用 VBA 获得与使用 Access 用户界面相同的结果?

【问题讨论】:

  • 你真的在使用sql server吗?屏幕截图中的所有内容均来自 Access。
  • 一个重要的区别是:您是否希望像文件 BLOB 一样存储文件(通过 VBA、其他编程语言等很容易使用 Blob,但通过 Access GUI 很难使用)或一个 OLE 包对象(很容易通过 GUI 使用,但几乎不可能通过 VBA 和很难通过 VBA 使用)?我可以向您展示如何将 OLE 包对象从文件加载到记录集中,但我强烈建议您使用普通文件 BLOB。
  • OLE 对象类似于嵌入的 Word 或 Excel 文档,而不是 BLOB。它们应该具有非常特定的文件格式,并且只能由其注册的应用程序打开。Zip 不是 OLE 对象。
  • 感谢大家提出非常好的问题并愿意提供帮助。
  • 对 Seam Lange:是​​的。我使用 SQL Server 作为后端。所有数据都保存在 SQL Server 中。我使用 Access 作为前端。

标签: sql-server object ms-access vba ole


【解决方案1】:

如果您想将文件存储为 OLE 包外壳对象,据我所知,进行一些 GUI 编码(使用 OLE 对象打开表单,然后使用它来存储文件)是唯一的方法。

创建一个名为 frmLoadOLEObj 的未绑定表单,上面有一个名为 MyBoundOLEFrame 的绑定 OLE 对象。

在表单上,​​添加以下代码:

Public Sub SaveOLEObj(rs As DAO.Recordset, fldName As String, FileName As Variant)
    'Save the position of the recordset
    Dim bkmrk As Variant
    bkmrk = rs.Bookmark
    'Bind the form to the recordset
    Set Me.Recordset = rs
    'Move the form to the saved position
    Me.Bookmark = bkmrk
    'Bind the OLE frame to the field
    MyBoundOLEFrame.ControlSource = fldName
    MyBoundOLEFrame.Class = "Package"
    'Load the attachment into the OLE frame
    MyBoundOLEFrame.SourceDoc = FileName
    MyBoundOLEFrame.Action = acOLECreateEmbed
End Sub

然后,将文件添加到记录中:

Dim rsa As DAO.Recordset
Set rsa = CurrentDb.OpenRecordset("ZipCodeAttachments", dbOpenDynaset, dbSeeChanges)
Dim frmOLE As New Form_frmLoadOLEObj
frmOLE.SaveOLEObj rs, "Attachments", Application.CurrentProject.Path & "\Attachments\537.zip"

如您所见,这是非常“hacky”的代码,因为它运行 GUI 操作,并且您的表单上的代码不是表单,而是真正的模块,但您需要一个表单来放置控件因为没有表单就无法控制。我宁愿每天都有一个 BLOB。

【讨论】:

  • 如果这完全回答了您的问题,请考虑接受它
  • Erik von Asmuth,我认为它确实回答了我的问题,我肯定会接受它作为答案。我想澄清一些事情,因为我面临一个重大问题,希望您能帮助我解决。提供的解决方案适用于大多数文件,但在大于约 20 MB 的文件上失败。语句 BoundOLEFrame.Action = acOLECreateEmbed 大约需要 2.5 分钟才能完成。它不会抛出任何异常,但是当执行以下 MoveNext 或任何重新定位语句时,它们会失败并出现运行时错误“3426”:“该操作已被关联对象取消。”
  • 由于上述结果,该对象似乎没有存储在数据库中,因为尝试使用 Access UI 打开它会导致错误:“Microsoft Access 与 OLE 通信时出现问题服务器或 ActiveX 控件。关闭 OLE 服务器并在 Microsoft Access 之外重新启动它。然后在 Microsoft Access 中再次尝试原始操作。怀疑这个问题可能与 ODBC 超时有关,默认设置为 60 秒,我尝试将当前数据库 QueryTimeout 设置为 600 秒。但这并没有帮助......任何建议将不胜感激。
  • 这听起来像是一个单独的问题。我建议您发布一个单独的问题。尝试为我提供所有必要的信息来复制它。我的数据库设置相当快,因此很难重现加载时间较长的问题
  • Erik,我与 SQL Server 的连接也非常快,但服务器是远程的,即使在本地数据库中加载 20+MB 的文件也需要相当长的时间。
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多