如何使用SMO从“创建脚本”创建“表更改”脚本

时间:2014-03-27 11:58:00

标签: sql vb.net smo

我最近需要在我的应用程序的MSSQL后端使用SMO运行创建表和更新表脚本,并且发现(不出意外)您不能像使用存储过程那样简单地用ALTER TABLE替换CREATE TABLE语句。 ..

所以我通过更改表格并在表格中选择“生成更改脚本”来了解SSMS如何做到这一点。然后,我使用此更改脚本来确定我的函数需要什么才能使其更通用化,并使用CREATE TABLE脚本文件中的整个表列表进行新安装。

对于任何感兴趣的人,在Answers下面是我的功能(在VB.NET中)使用SMO。它绝不是完美的,但我希望如果不解决同样的问题,你会发现它是一个很好的起点。

1 个答案:

答案 0 :(得分:1)

我的例子假设如下:

  • 您已使用SMO连接到服务器和本地数据库,并将本地数据库分配给“dbLocal”变量。
  • 您的项目包含带有CREATE TABLE语句的SQL脚本文件(作为字符串参数传递给函数)

(我已经包含了我的GetFileContents函数以防万一)

Public Function UpdateCreateTables(ByVal SQLFilePath As String) As Boolean
    'Open CREATE TABLE Script file
    Dim strFilePath As String = SQLFilePath
    Dim strErr As String = ""
    Dim encEncoding As System.Text.Encoding = Nothing
    Dim strContents As String = GetFileContents(strFilePath, encEncoding, strErr)
    If strErr = "" Then
        'Successfully Read

        'Prepare
        Dim SQLSCRIPT As String = "" & _
            "BEGIN TRANSACTION" & _
                "SET QUOTED_IDENTIFIER ON" & _
                "SET ARITHABORT ON" & _
                "SET NUMERIC_ROUNDABORT OFF" & _
                "SET CONCAT_NULL_YIELDS_NULL ON" & _
                "SET ANSI_NULLS ON" & _
                "SET ANSI_PADDING ON" & _
                "SET ANSI_WARNINGS ON" & _
            "COMMIT"

        'Run Transaction Script
        dbLocal.ExecuteNonQuery(SQLSCRIPT, Microsoft.SqlServer.Management.Common.ExecutionTypes.ContinueOnError)

        'Inject All Table Names with a "TMP_" prefix
        strContents = strContents.Replace("CREATE TABLE [dbo].[", "CREATE TABLE [dbo].[TMP_")
        'Inject All Constraints with a TMP_ Prefix
        strContents = strContents.Replace("CONSTRAINT [PK_", "CONSTRAINT [PK_TMP_")

        SQLSCRIPT = strContents

        'Run Script (Create TMP tables)
        dbLocal.ExecuteNonQuery(SQLSCRIPT, Microsoft.SqlServer.Management.Common.ExecutionTypes.ContinueOnError)

        'Loop through Each TMP table and copy original table data across
        For Each dbTable As Table In dbLocal.Tables()
            If dbTable.Name.Contains("TMP_") Then
                Dim strTable_TempName As String = dbTable.Name
                Dim strTable_OrigName As String = Strings.Replace(dbTable.Name, "TMP_", "")

                Dim dbTempTable As Table = dbLocal.Tables(strTable_TempName)
                Dim dbOrigTable As Table = dbLocal.Tables(strTable_OrigName)

                'Get TmpTable Column Names
                Dim strTempTable_Columns As String = ""
                Dim strOrigTable_Columns As String = ""
                For Each col As Column In dbTempTable.Columns
                    strTempTable_Columns = strTempTable_Columns & col.Name & ", "
                    'Find Matching Column in Orig Table
                    If dbOrigTable.Columns.Contains(col.Name) Then
                        strOrigTable_Columns = strOrigTable_Columns & col.Name & ", "
                    Else
                        strOrigTable_Columns = strOrigTable_Columns & "NULL" & ", "
                    End If
                Next
                strTempTable_Columns = Strings.Left(strTempTable_Columns, strTempTable_Columns.Length - 2) 'Remove trailing comma+space
                strOrigTable_Columns = Strings.Left(strOrigTable_Columns, strOrigTable_Columns.Length - 2) 'Remove trailing comma+space

                'alter LOCK_ESCALATION
                dbTempTable.LockEscalation = LockEscalationType.Table

                'Get Primary Key
                Dim PK_Name As String = ""
                For Each oIndex As Index In dbTempTable.Indexes
                    If oIndex.IndexKeyType = IndexKeyType.DriPrimaryKey Then
                        ' Primary key found
                        PK_Name = oIndex.Name
                    End If
                Next

                SQLSCRIPT = "" & _
                    "BEGIN TRANSACTION" & vbCrLf & _
                        "GO" & vbCrLf & _
                        "SET IDENTITY_INSERT dbo." & strTable_TempName & " ON" & vbCrLf & _
                        "GO" & vbCrLf & _
                            "IF EXISTS(SELECT * FROM dbo." & strTable_OrigName & ")" & vbCrLf & _
                            "   EXEC('INSERT INTO dbo." & strTable_TempName & " (" & strTempTable_Columns & ")" & vbCrLf & _
                            "       SELECT " & strOrigTable_Columns & " FROM dbo." & strTable_OrigName & " WITH (HOLDLOCK TABLOCKX)')" & vbCrLf & _
                            "   GO" & vbCrLf & _
                        "SET IDENTITY_INSERT dbo." & strTable_TempName & " OFF" & vbCrLf & _
                        "GO" & vbCrLf & _
                        "DROP TABLE dbo." & strTable_OrigName & "" & vbCrLf & _
                        "GO" & vbCrLf & _
                        "EXECUTE sp_rename N'dbo." & PK_Name & "', '" & Replace(PK_Name, "TMP_", "") & "', 'OBJECT'" & vbCrLf & _
                        "GO" & vbCrLf & _
                        "EXECUTE sp_rename N'dbo." & strTable_TempName & "', N'" & strTable_OrigName & "', 'OBJECT'" & vbCrLf & _
                        "GO" & vbCrLf & _
                    "COMMIT"

                'Run Transaction Script
                dbLocal.ExecuteNonQuery(SQLSCRIPT, Microsoft.SqlServer.Management.Common.ExecutionTypes.ContinueOnError)

            End If
        Next

        UpdateCreateTables = True
    Else
        UpdateCreateTables = False
    End If

End Function
Public Function GetFileContents(ByVal FullPath As String, ByRef encEncoding As System.Text.Encoding, Optional ByRef ErrInfo As String = "") As String
    Dim strContents As String
    Dim objReader As StreamReader

    Try
        objReader = New StreamReader(FullPath, True)
        encEncoding = objReader.CurrentEncoding
        strContents = objReader.ReadToEnd()
        objReader.Close()
        Return strContents
    Catch Ex As Exception
        ErrInfo = Ex.Message
        Return Nothing
    End Try
End Function