MS Access связан с представлениями SQL-сервера - PullRequest
4 голосов
/ 24 июня 2009

у нас есть проблема с базой данных доступа, которую мы обновляем, чтобы использовать SQL Server в качестве хранилища данных.

Эта конкретная база данных связана с базами данных 2 sql, поэтому я подумал, что для упрощения у нас есть представление в основной базе данных, которое связано с каждой таблицей в дополнительной базе данных. Таким образом, доступ должен был бы общаться только с одной базой данных SQL.

Когда мы связали доступ к представлениям базы данных, мы выбираем, какие поля были первичными ключами, чтобы представления не были доступны только для чтения. У нас есть стандартный код, который обновляет все ссылки, когда база данных открывается для получения любых изменений, и связанные представления становятся доступными только для чтения, поскольку информация первичного ключа теряется.

Есть ли способ обновления ссылок на представления при сохранении информации первичного ключа?

John

Ответы [ 3 ]

4 голосов
/ 24 июня 2009

Я включил всю свою функцию переподключения ODBC ниже. Эта функция основана на идее, что у меня есть таблица rtblODBC, в которой хранится вся информация, необходимая для переподключения. Если вы реализуете эту функцию, вам НЕ нужно будет беспокоиться о подключении к нескольким базам данных SQL, поскольку это происходит плавно, при этом каждая таблица для повторного подключения имеет собственную строку подключения.

Когда вы приблизитесь к концу, вы увидите, что я использую DAO для воссоздания первичных ключей с помощью db.Execute "CREATE INDEX" & sPrimaryKeyName & "ON" & sLocalTableName & "(" & sPrimaryKeyField & ") WITH PRIMARY;"

Если у вас есть какие-либо вопросы, пожалуйста, задавайте.

Public Function fnReconnectODBC( _
    Optional bForceReconnect As Boolean _
    ) As Boolean
    ' Comments  :
    ' Parameters: bForceReconnect -
    ' Returns   : Boolean -
    ' Modified  :
    ' --------------------------------------------------'

    On Error GoTo Err_fnReconnectODBC

    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim tdf As DAO.TableDef
    Dim sPrimaryKeyName As String
    Dim sPrimaryKeyField As String
    Dim sLocalTableName As String
    Dim strConnect As String
    Dim varRet As Variant

    Dim con As ADODB.Connection
    Dim rst As ADODB.Recordset
    Dim sSQL As String

    If IsMissing(bForceReconnect) Then

        bForceReconnect = False

    End If

    sSQL = "SELECT rtblODBC.LocalTableName, MSysObjects.Name, MSysObjects.ForeignName, rtblODBC.SourceTableName, MSysObjects.Connect, rtblODBC.ConnectString " _
         & "FROM MSysObjects RIGHT JOIN rtblODBC ON MSysObjects.Name = rtblODBC.LocalTableName " _
         & "WHERE (((rtblODBC.ConnectString)<>'ODBC;' & [Connect]));"

    Set con = Access.CurrentProject.Connection
    Set rst = New ADODB.Recordset

    rst.Open sSQL, con, adOpenDynamic, adLockOptimistic

        'Test the recordset to see if any tables in rtblODBC (needed tables) are missing from the MSysObjects (actual tables)
        If rst.BOF And rst.EOF And bForceReconnect = False Then

            'No missing tables identified
            fnReconnectODBC = True

        Else

            'Table returned information, we don't have a perfect match, time to relink
            Set db = CurrentDb
            Set rs = db.OpenRecordset("rtblODBC", dbOpenSnapshot)

                'For each table definition in the database collection of tables
                For Each tdf In db.TableDefs

                    'Set strConnect variable to table connection string
                    strConnect = tdf.Connect

                    If Len(strConnect) > 0 And Left(tdf.Name, 1) <> "~" Then

                        If Left(strConnect, 4) = "ODBC" Then

                            'If there is a connection string, and it's not a temp table, and it IS an odbc table
                            'Delete the table
                            DoCmd.DeleteObject acTable, tdf.Name

                        End If

                    End If

                Next

                'Relink tables from rtblODBC
                With rs

                    .MoveFirst

                    Do While Not .EOF

                        Set tdf = db.CreateTableDef(!localtablename, dbAttachSavePWD, !SourceTableName, !ConnectString)

                        varRet = SysCmd(acSysCmdSetStatus, "Relinking '" & !SourceTableName & "'")

                        db.TableDefs.Append tdf
                        db.TableDefs.Refresh

                        If Len(!PrimaryKeyName & "") > 0 And Len(!PrimaryKeyField & "") > 0 Then

                            sPrimaryKeyName = !PrimaryKeyName
                            sPrimaryKeyField = !PrimaryKeyField
                            sLocalTableName = !localtablename

                            db.Execute "CREATE INDEX " & sPrimaryKeyName & " ON " & sLocalTableName & "(" & sPrimaryKeyField & ")WITH PRIMARY;"

                        End If

                        db.TableDefs.Refresh

                        .MoveNext

                    Loop

                End With

            subTurnOffSubDataSheets

            fnReconnectODBC = True

        End If

    rst.Close
    Set rst = Nothing

    con.Close
    Set con = Nothing


Exit_fnReconnectODBC:

    Set tdf = Nothing
    Set rs = Nothing
    Set db = Nothing

    varRet = SysCmd(acSysCmdClearStatus)

    Exit Function

Err_fnReconnectODBC:

    fnReconnectODBC = False

    sPrompt = "Press OK to continue."
    vbMsg = MsgBox(sPrompt, vbOKOnly, "Error Reconnecting")
    If vbMsg = vbOK Then

        Resume Exit_fnReconnectODBC

    End If

End Function
1 голос
/ 24 июня 2009

Большая часть кода без DSN, который повторно связывает таблицы доступа с сервером SQL, часто сначала удаляет ссылки, а затем воссоздает ссылку. Затем код устанавливает строку подключения. Таким образом, именно удаление приводит к потере того, чем был / является первичный ключ.

Я действительно рекомендую изменить код повторной ссылки, чтобы не удалять ссылки на таблицы.

Попробуйте что-то вроде:

For Each tdfCurrent In dbCurrent.TableDefs
   If Len(tdfCurrent.Connect) > 0 Then
      If Left$(tdfCurrent.Connect, 5) = "ODBC;" Then
         strCon = "ODBC;DRIVER={sql server};" & _
           "SERVER=" & ServerName & ";" & _
           "DATABASE=" & DatabaseName & ";" & _
           "UID=" & UserID & ";" & _
           "PWD=" & USERpw & ";" & _
           "APP=Microsoft Office 2003;" & _
           "WSID=" & WSID & ";"
        End If
     End If
     tdfCurrent.Connect = strCon
     tdfCurrent.RefreshLink
  End If
Next tdfCurrent
0 голосов
/ 29 июля 2009

Для меня это работает немного лучше (обратите внимание на перемещенный конец if's):

Dim dbCurrent As Database
Set dbCurrent = CurrentDb()

StatusList.SetFocus
StatusList.AddItem ("starting... ")
I = DoEvents()
Dim tdfCurrent As DAO.TableDef
For Each tdfCurrent In dbCurrent.TableDefs
   If Len(tdfCurrent.Connect) > 0 Then
      If Left$(tdfCurrent.Connect, 5) = "ODBC;" Then
         strCon = "ODBC;DRIVER={sql server};" & _
           "SERVER=" & ServerName & ";" & _
           "DATABASE=" & DatabaseName & ";" & _
           "UID=" & UserID & ";" & _
           "PWD=" & USERpw & ";" & _
           "APP=Microsoft Office 2003;" & _
           "WSID=" & WSID & ";"

           StatusList.AddItem ("fixing " & tdfCurrent.Name)
        tdfCurrent.Connect = strCon
        tdfCurrent.RefreshLink
     End If
  End If
  I = DoEvents()
Next tdfCurrent

  StatusList.AddItem ("----Done.")

Проверка ODBC верна, хотя "ODBC;" часть не отображается в представлении MSysObjects.

...