【问题标题】:Read Permission problem on .NET Embedded Resource - Access DB file & SSIS.NET Embedded Resource 上的读取权限问题 - 访问 DB 文件和 SSIS
【发布时间】:2025-12-05 19:35:02
【问题描述】:

我目前正在创建动态 SSIS 包,用于在 SQL Server 和多个 Access DB 文件之间导入/导出和访问数据。 (如果您想获得技术知识,请使用 Jet 文件。)

无论如何,只要我的 SSIS 包具有到 Access 文件的硬编码连接字符串,测试期间一切都会成功。这很棒,而且效果很好。我对此很满意。

当我将我的 VB.NET 应用程序更改为使用动态连接字符串到 Access DB 文件(目标文件,数据将被放置的位置)时,问题就开始了。我将 Access DB 文件作为“嵌入式资源”存储在我的应用程序中。

这是我用来创建访问目标文件的代码:

    Public Sub CreateDestinationFile(ByVal path As String)

    'Create destination file from embedded project resources 
    Dim asm = System.Reflection.Assembly.GetExecutingAssembly()
    Dim objStream As System.IO.Stream = asm.GetManifestResourceStream("XXX.XXX_Export.mdb")
    Dim abytResource(objStream.Length) As [Byte]
    Dim intLength As Integer = objStream.Read(abytResource, 0, objStream.Length)
    Dim objFileStream = New FileStream(path + "XXX_Export.mdb", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)

    Try

        While intLength > 0
            'write filestream to create Access DB file
            objFileStream.Write(abytResource, 0, Convert.ToInt32(objStream.Length))
            intLength = objStream.Read(abytResource, 0, objStream.Length)
        End While

        'close the file stream
        objFileStream.Close()

    Catch ex As Exception
        'write error log here - ** omitted
    Finally
        asm = Nothing
        objStream = Nothing
        objFileStream = Nothing
    End Try

End Sub

这可以正常工作,并且确实会产生正确的结果,无论我在哪里提供路径,都会生成一个 Access DB 文件。当我的 SSIS 包具有硬编码的连接字符串时,这很有效。

一旦我将连接字符串更改为动态的,并重新运行完全相同的测试,我就会收到以下错误:

“无法读取记录;‘MSysAccessObjects’没有读取权限”

我的 SSIS 包中的连接字符串正则表达式如下所示:

--SQL connection string
"Data Source=" + @[User::sourceDatabaseLocation] + ";User ID=" + @[User::sourceDBUserID] + ";Password=" + @[User::sourceDBPassword] + ";Initial Catalog=" + @[User::sourceDBName] + ";Provider=SQLOLEDB.1;Persist Security Info=True;Auto Translate=False;"

--Access connection string
"Data Source=" + @[User::destinationDatabasePath] + ";Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Password=;"

当我导航到本地硬盘驱动器上的此文件并尝试打开它时,它提示我它处于不可恢复状态并修复它,但它从未成功过。

  1. 我是否忽略了有关文件创建的某些内容? (IO?)
  2. 我是否忽略了有关嵌入式资源的某些内容? (它们对我来说似乎很直接,但也许我忽略了一些明显的东西?)
  3. 我的文件状态是否已损坏?我可以使用 MS Access 在 VS.NET IDE 和本地打开它。
  4. 是否值得重新创建此 Access 文件?我读过您可以将架构复制到新文件以避免修复?这听起来太冒险了!!

最初我认为这是一个权限错误,关于 Access DB 文件的用户角色和 SSIS 试图使用它。但我不认为是这样。用户设置为管理员并且应该(理论上)工作。

我认为要破解/修复此问题,我目前将尝试不使用嵌入式资源。我将使用 FileIO 调用将文件显式移动到我想要的文件夹并从那里填充它。有谁知道为什么嵌入式资源数据库文件不起作用,但是当不是从嵌入式资源生成时,同一个文件确实起作用?当我从资源创建文件时,是否有未完成的内容?

非常感谢任何反馈或建议。也欢迎任何问题。谢谢。

**** 更新/07/18/2009:**

我修改了我的 [CreateDestinationFile] 例程以执行直接文件/IO 复制,而不是使用嵌入式资源。

下面是代码:

        Dim sPath As String = My.Application.Info.DirectoryPath + "\databasenamehere.mdb"

        FileIO.FileSystem.CopyFile(sPath, path + "databasenamehere.mdb", True)

该文件已从项目中正确复制,但我现在收到此错误:

“发生 OLE DB 错误。错误代码:0x80040E09。OLE DB 记录可用。来源:“Microsoft JET 数据库引擎” Hresult:0x80040E09 描述:“无法读取记录; 'TABLE_XXXXX' 没有读取权限。”

这让我相信 SSIS 没有适当的权限来使用我的本地 MS Access DB 作为目标文件。

这对我来说很奇怪,因为如果我将连接字符串硬编码到我的 SSIS 包中,相同的文件也可以工作。这是怎么回事?

正如您在我的连接字符串表达式中看到的,我有 [Admin] 作为用户。所以这应该有效,对吧?此外,这个问题的另一个可能的罪魁祸首是这是在 Access 2003 中创建的旧版 MS Access DB,而我在我的机器上使用的是 Access 2007。帮忙?

【问题讨论】:

    标签: vb.net file-io ssis embedded-resource jet


    【解决方案1】:

    这不会是一个非常有帮助的答案,我不在你工作的环境中工作,所以永远不必这样做,但我想到了几件事。

    您使用管理员作为用户和空白密码,这是默认的 Jet 登录,但它可能使用了错误的工作组文件。我记得其他 * 海报在通过某些方法连接到 Jet 文件时遇到问题,这些方法在连接字符串中没有工作组文件参数。您是否尝试过创建一个 ODBC DSN,然后尝试连接到它? DSN 允许您指定工作组文件,以便可以改善问题。然后,您可以尝试将生成的连接字符串转换为无 DSN 的连接字符串,然后将其用作参数化连接字符串的模型。

    【讨论】:

    • 感谢您的回复。我玩弄了许多解决此问题的方法。您的回复确实让我更仔细地查看了连接字符串参数,但不幸的是没有任何成功。我的数据库一开始就损坏了,这是我的问题。尽管我可以查看其中的所有数据,但它已损坏但肉眼无法看到。谢谢你的帮助,它确实让我想到了我没想到的方向。干杯
    • 您可能应该更新您的原始问题,以反映您解决问题的事实,即您更正了损坏。
    【解决方案2】:

    为了解决这个问题,我最终使用了在初始项目收集期间提供给我的模板文件。

    我使用的 .mdb 文件已经针对众多应用程序和测试项目进行了开发和测试。该文件从第一天起就存在问题。

    我对该文件的第一个问题是它的大小为 80 mb。这对我来说很奇怪,因为里面的数据很少。一旦我意识到我需要“压缩和修复”,它就会将其大小减小到不到 200 kb。这让我很困惑。但是我继续使用这个文件进行进一步的开发,现在我意识到这是一个很大的禁忌。

    我最终决定从我的电子邮件中挖掘出我继承这个项目时提供的原始 .mdb 文件。这个原始的 .mdb 仍然不理想,因为它在我要导出到的表中包含数据。我不得不手动从中删除数千条记录。一旦我这样做了,我的 SSIS 包就神奇地工作了。我现在可以动态地将数据从 SQL 导出到 Access。

    这是我的 VB.NET 执行的 SSIS 包,它使用动态连接字符串,由 [app.config] 配置文件提供:

    Public Function ExecuteSSISExportPackage(ByVal parameterValue1 As String, ByVal destinationDatabasePath As String) As Integer
    
        Dim pkg As New Package
        Dim app As New Microsoft.SqlServer.Dts.Runtime.Application
        Dim pkgResults As DTSExecResult
        Dim result As Integer = 1 'defaults to failure
        Dim eventListener As New EventListener()
    
        'create SSIS variables for dynamic parameters, retrieved from the appSettings in the [app.config] file
        Dim SSISPackagePassword As String = ConfigurationManager.AppSettings.Item("SSISPackagePassword")
        Dim SSISExportPackagePath As String = ConfigurationManager.AppSettings.Item("SSISExportPackagePath")
        Dim SSISExportPackageServerName As String = ConfigurationManager.AppSettings.Item("SSISExportPackageServerName")
        Dim SSISExportPackageServerUserName As String = ConfigurationManager.AppSettings.Item("SSISExportPackageServerUserName")
        Dim SSISExportPackageServerPassword As String = ConfigurationManager.AppSettings.Item("SSISExportPackageServerPassword")
        Dim SSISExportPackageDestinationDBName As String = ConfigurationManager.AppSettings.Item("SSISExportPackageDestinationDBName")
    
        Try
            'set package password
            app.PackagePassword = SSISPackagePassword
            pkg.PackagePassword = SSISPackagePassword
    
            'load package from SQL server
            pkg = app.LoadFromSqlServer(SSISExportPackagePath, SSISExportPackageServerName, SSISExportPackageServerUserName, SSISExportPackageServerPassword, eventListener)
    
            'set package-level variables, to supply to the stored procedure parameters/sql calls in the SSIS Export package
            pkg.Variables("xxxx").Value = parameterValue1
    
            'set the package-level variable to supply the Access DB's (SSIS destination) file path
            Dim databaseName As String = ConfigurationManager.AppSettings.Item("XXXClientDatabaseName")
            pkg.Variables("destinationDatabasePath").Value = "C:\" + databaseName 
    
            'Dynamic SQL source connection string values
            pkg.Variables("sourceDatabaseLocation").Value = SSISExportPackageServerName
            pkg.Variables("sourceDBUserID").Value = SSISExportPackageServerUserName
            pkg.Variables("sourceDBName").Value = SSISExportPackageDestinationDBName
            pkg.Variables("sourceDBPassword").Value = SSISExportPackageServerPassword
    
            'Execute the Import SSIS package, add an eventListener object for SSIS reflection
            pkgResults = pkg.Execute(Nothing, Nothing, eventListener, Nothing, Nothing)
    
            'Package execution results
            Select Case pkgResults
    
                Case DTSExecResult.Success
                    result = 0
    
                Case DTSExecResult.Failure
                    result = 1
    
            End Select
    
        Catch ex As Exception
    
            'Log the exception error here - omitted
    
        Finally
            app = Nothing
            pkg = Nothing
        End Try
    
        Return result
    
    End Function
    

    【讨论】:

    • 我很抱歉这个例子不在 C#.NET 中。 VB.NET 不是我首选的 .NET 语言。