0

我目前正在创建动态 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。帮助?

4

2 回答 2

0

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

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

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

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

这是我对 SSIS 包的 VB.NET 执行,它使用 [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
于 2009-07-29T19:27:44.233 回答
0

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

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

于 2009-07-16T20:36:16.453 回答