11

データベースを右クリックして、[タスク]メニューの[スクリプトの生成]から手動でスクリプトを生成しました。

今私の問題は、c#コードを介してそのスクリプトを生成することです...

私の質問は

  1. C#コードを介して生成することは可能ですか?

  2. 完了するためのヒントを教えてください。

あなたの貴重な提案とコマンドを待っています。

4

6 に答える 6

19

すでに述べたように、これを行うにはSMOを使用します。これは、C#を使用してデータベースのスクリプトを作成する例です。いくつかのオプションについて説明しましたが、@ David Brabantの投稿にあるように、多くのオプションの値を指定できます。 。

public string ScriptDatabase()
{
      var sb = new StringBuilder();

      var server = new Server(@"ServerName");
      var databse = server.Databases["DatabaseName"];

      var scripter = new Scripter(server);
      scripter.Options.ScriptDrops = false;
      scripter.Options.WithDependencies = true;
      scripter.Options.IncludeHeaders = true;
      //And so on ....


      var smoObjects = new Urn[1];
      foreach (Table t in databse.Tables)
      {
          smoObjects[0] = t.Urn;
          if (t.IsSystemObject == false)
          {
              StringCollection sc = scripter.Script(smoObjects);

              foreach (var st in sc)
              {
                  sb.Append(st);
              }
           }
       }
            return sb.ToString();
 }

このリンクは、ストアドプロシージャの取得とスクリプト作成に役立つ場合があります

于 2012-08-27T11:51:55.273 に答える
5

sql smoを使用して、 SQL ServerEnterpriseManagerで使用可能なすべての機能を基本的に実装できます。ここに素晴らしいチュートリアルがあります。

編集: PowerShellでSMOを使用した例

function SQL-Script-Database
{
    <#
    .SYNOPSIS
    Script all database objects for the given database.

    .DESCRIPTION
    This  function scripts all database objects  (i.e.: tables,  views, stored
    procedures,  and user defined functions) for the specified database on the
    the given server\instance. It creates a subdirectory per object type under 
    the path specified.

    .PARAMETER savePath
    The root path where to save object definitions.

    .PARAMETER database
    The database to script (default = $global:DatabaseName)

    .PARAMETER DatabaseServer 
    The database server to be used (default: $global:DatabaseServer).

    .PARAMETER InstanceName 
    The instance name to be used (default: $global:InstanceName).

    .EXAMPLE
    SQL-Script-Database c:\temp AOIDB
    #>

    param (
        [parameter(Mandatory = $true)][string] $savePath,
        [parameter(Mandatory = $false)][string] $database = $global:DatabaseName,
        [parameter(Mandatory = $false)][string] $DatabaseServer = $global:DatabaseServer,
        [parameter(Mandatory = $false)][string] $InstanceName = $global:InstanceName
    )

    try
    {
        if (!$DatabaseServer -or !$InstanceName)
            { throw "`$DatabaseServer or `$InstanceName variable is not properly initialized" }

        $ServerInstance = SQL-Get-Server-Instance $DatabaseServer $InstanceName

        [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null

        $s = New-Object Microsoft.SqlServer.Management.Smo.Server($ServerInstance)
        $db = $s.databases[$database]

        $objects = $db.Tables
        $objects += $db.Views
        $objects += $db.StoredProcedures
        $objects += $db.UserDefinedFunctions

        $scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($s)

        $scripter.Options.AnsiFile = $true
        $scripter.Options.IncludeHeaders = $false
        $scripter.Options.ScriptOwner = $false
        $scripter.Options.AppendToFile = $false
        $scripter.Options.AllowSystemobjects = $false
        $scripter.Options.ScriptDrops = $false
        $scripter.Options.WithDependencies = $false
        $scripter.Options.SchemaQualify = $false
        $scripter.Options.SchemaQualifyForeignKeysReferences = $false
        $scripter.Options.ScriptBatchTerminator = $false

        $scripter.Options.Indexes = $true
        $scripter.Options.ClusteredIndexes = $true
        $scripter.Options.NonClusteredIndexes = $true
        $scripter.Options.NoCollation = $true

        $scripter.Options.DriAll = $true
        $scripter.Options.DriIncludeSystemNames = $false

        $scripter.Options.ToFileOnly = $true
        $scripter.Options.Permissions = $true

        foreach ($o in $objects | where {!($_.IsSystemObject)}) 
        {
            $typeFolder=$o.GetType().Name 

            if (!(Test-Path -Path "$savepath\$typeFolder")) 
                { New-Item -Type Directory -name "$typeFolder"-path "$savePath" | Out-Null }

            $file = $o -replace "\[|\]"
            $file = $file.Replace("dbo.", "")

            $scripter.Options.FileName = "$savePath\$typeFolder\$file.sql"
            $scripter.Script($o)
        }
    }

    catch
    {
        Util-Log-Error "`t`t$($MyInvocation.InvocationName): $_"
    }
}
于 2012-08-27T10:45:11.583 に答える
4

@SamiAnswerに基づく

データベースのすべてのスクリプト(テーブル、ビュー、ストアドプロシージャ、ユーザー、UserDefinedFunctions)を生成するこの単純な関数を作成しました

最初に:必要なアセンブリを取得します

C:\ Program Files \ Microsoft SQL Server \ 100 \ SDK \ Assemblyは、正しいフォルダーの場所です(または、64ビットシステムではC:\ Program Files(x86)\ Microsoft SQL Server \ 100 \ SDK \ Assembly)。

以下への参照を追加する必要があります。

Microsoft.SqlServer.ConnectionInfo.dll

Microsoft.SqlServer.Smo.dll

Microsoft.SqlServer.Management.Sdk.Sfc.dll

Microsoft.SqlServer.SqlEnum.dll

2番目:この関数を使用します

  public static string ScriptDatabase() 
{
    // For Me Server is ".\SQLExpress" You may have changed
    Server myServer = new Server(@".\SQLExpress");
    Scripter scripter = new Scripter(myServer);

    //Databas1 is your database Name Thats Changable

    Database myAdventureWorks = myServer.Databases["MyDBName"];
    /* With ScriptingOptions you can specify different scripting  
    * options, for example to include IF NOT EXISTS, DROP  
    * statements, output location etc*/
    ScriptingOptions scriptOptions = new ScriptingOptions();
    scriptOptions.ScriptDrops = true;
   // scriptOptions.ScriptData = true;
    scriptOptions.ScriptSchema = true;


    scriptOptions.IncludeIfNotExists = true;
    string scrs = "";
    string tbScr = "";
    foreach (Table myTable in myAdventureWorks.Tables)
    {
        /* Generating IF EXISTS and DROP command for tables */
        StringCollection tableScripts = myTable.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script + "\n\n";

        /* Generating CREATE TABLE command */
        tableScripts = myTable.Script();
        foreach (string script in tableScripts)
            tbScr += script + "\n\n";
    }


    foreach (StoredProcedure mySP in myAdventureWorks.StoredProcedures)
    {
        /* Generating IF EXISTS and DROP command for StoredProcedures */
        StringCollection tableScripts = mySP.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script + "\n\n";

        /* Generating CREATE StoredProcedure command */
        tableScripts = mySP.Script(scriptOptions);
        foreach (string script in tableScripts)
            tbScr += script + "\n\n";
    }

    foreach (View myView in myAdventureWorks.Views)
    {
        /* Generating IF EXISTS and DROP command for Views */
        StringCollection tableScripts = myView.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script + "\n\n";

        /* Generating CREATE Views command */
        tableScripts = myView.Script(scriptOptions);
        foreach (string script in tableScripts)
            tbScr += script+"\n\n";
    }


    foreach (Microsoft.SqlServer.Management.Smo.User user in myAdventureWorks.Users)
    {
        /* Generating IF EXISTS and DROP command for Users */
        StringCollection tableScripts = user.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script+"\n\n";

        /* Generating CREATE Users command */
        tableScripts = user.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script + "\n\n";
    }



    foreach (Microsoft.SqlServer.Management.Smo.UserDefinedFunction userF in myAdventureWorks.UserDefinedFunctions)
    {
        /* Generating IF EXISTS and DROP command for UserDefinedFunctions */
        StringCollection tableScripts = userF.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script + "\n\n";

        /* Generating CREATE UserDefinedFunction command */
        tableScripts = userF.Script(scriptOptions);
        foreach (string script in tableScripts)
            scrs += script + "\n\n";
    } 

    // For WinForms
    return (scrs + "\n\n" + tbScr);
    //For Console
    //Console.WriteLine(scrs + "\n\n" + tbScr);
}
于 2015-09-06T06:41:56.753 に答える
2

私は上記の回答を使用して、c#でこれを行うためのコマンドラインプログラムを作成してきましたが、上記の回答を少し拡張したいと思いました。

使用する必要のあるスキーマだけでなくデータも出力する場合は、次のようにします。

scripter.EnumScript(something);
//instead of 
scripter.Script(something);

スクリプトメソッドは、IncludeDataオプションをチェックし、設定されている場合は例外をスローしますが、使用する適切なメソッドを見つけるには、Googleにアクセスする必要があります。興味深いAPIデザイン!

データベース内の関連リストは次のとおりです。

        database.Tables
        database.Schemas
        database.Views
        database.StoredProcedures
        database.UserDefinedFunctions
        database.Users
        database.Roles
        database.Sequences

それは網羅的ではないかもしれませんが。

システムオブジェクトを取り除く

これらのオブジェクトのリストはすべてカスタムタイプであるIEnumerable but not IEnumerable<T>ため、linqを実行することはできません。これは、それらにどのタイプが含まれているかを調べ、foreachの暗黙的なキャストを使用してそれらを取得する必要があることも意味します。私はこれまでc#でそれを使用したことはありませんでしたが、これはおそらくフレームワーク2を対象としていると思います。

それらの多くにはIsSystemObjectと呼ばれるプロパティもありますが、これはインターフェイスを実装していません。最初は、すべてのシステムオブジェクトを取り除くのは本当に苦痛のように見えますが、次のオプションを設定することで、すべてを一挙にカリングできます。

options.AllowSystemObjects = false;

これは、システムの役割を手動で実行する必要がある役割を除いて、すべてで機能します。

        foreach (DatabaseRole role in database.Roles)
        {
            if(role.IsFixedRole)
                continue;

            list.Add(role);
        }

出力用のオブジェクトの追加

私が使用したプロセスは、 UrnCollectionを作成してから、別のリストをコレクションに追加することでした。このような:

        var list = new UrnCollection();

        foreach (Schema schema in database.Schemas)
            list.Add(schema.Urn);
        //... more of these

        scripter.EnumScript(list);

オプション

そこから、必要な出力を再作成するために設定するオプションを理解する必要があります。覚えておくべきいくつかのこと:

  • インデックス、トリガー、制約などはオプションによって設定され、ファーストクラスのオブジェクトとしては扱われません。
  • SSMSのUIではシーケンスをまったく生成できないため、これらを使用している場合は、出力に少なくともいくつかの差分が必要です。

外部キーなどを取り出す方法の詳細については、この投稿を参照してください。

健康警告

バックアップと復元では望みどおりの結果が得られないと思ったので、データベースをコピーする方法としてこれを検討し始めました。smoパスをかなり長い道のりをたどり、多くの問題に遭遇した後、私は少し再評価を行い、そのユースケースではバックアップと復元がはるかに簡単であることがわかりました。

于 2014-05-23T09:20:58.910 に答える
1

うまくいけば、それはあなたと今後の人たちを導くでしょう。

次の必要な名前空間を含めるには、プロジェクトに次の4つの参照を追加する必要があります

参照を追加するには

  1. ソリューションエクスプローラーでプロジェクトを右クリックし、[参照の追加]を選択します
  2. 上部のメニューから[参照]をクリックします
  3. そして、以下の指示に従って4つのdllファイルを選択します

参照Microsoft.SqlServer.Smo.dll

名前空間

using System.Data.SqlClient;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;

次に、関数またはボタンクリックイベントで次のコードを使用します

        // For Me Server is ".\SQLExpress" You may have changed
        Server myServer = new Server(@".\SQLExpress");
        Scripter scripter = new Scripter(myServer);

        //Databas1 is your database Name Thats Changable

        Database myAdventureWorks = myServer.Databases["Database1"];
        /* With ScriptingOptions you can specify different scripting  
        * options, for example to include IF NOT EXISTS, DROP  
        * statements, output location etc*/
        ScriptingOptions scriptOptions = new ScriptingOptions();
        scriptOptions.ScriptDrops = true;
        scriptOptions.IncludeIfNotExists = true;
        string scrs = "";
        string tbScr = "";
        foreach (Table myTable in myAdventureWorks.Tables)
        {
            /* Generating IF EXISTS and DROP command for tables */
            StringCollection tableScripts = myTable.Script(scriptOptions);
            foreach (string script in tableScripts)
                scrs += script;

            /* Generating CREATE TABLE command */
            tableScripts = myTable.Script();
            foreach (string script in tableScripts)
                tbScr += script;
        }
        // For WinForms
        MessageBox.Show(scrs + "\n\n" + tbScr);
        //For Console
        //Console.WriteLine(scrs + "\n\n" + tbScr);

これには、http: //www.mssqltips.com/sqlservertip/1833/generate-scripts-for-database-objects-with-smo-for-sql-server/ David Brabantによる回答(上記)と上記のSOリンクが含まれていました。

コードブロック2が使用されます。今、あなたは他の人も使うことができます

そこにmyserverが見つかりませんでしたが、上記のコードでも解決されています。

于 2012-08-27T14:49:17.490 に答える
0

ストアドプロシージャのスクリプトを取得する例。注:文字列操作で「GO」と「ALTER」を追加しています。なぜGOが生成されないのかを理解するために6時間を費やしました。Microsoftの反撃:ライブラリSMO(サーバー管理オブジェクト)は非常に時間がかかり、バグが多く、操作が困難です。

var dbObj = database.StoredProcedures[name, schema];
if (dbObj != null)
{
    Console.WriteLine(dbObj);

    var script = new StringBuilder();
    script.AppendLine("USE LifelongLearning");
    script.AppendLine("GO");
    script.AppendLine();

    StringCollection scripts = dbObj.Script(scriptOptionsCreate);
    foreach (string s in scripts)
    {
        if (s.Contains("CREATE ", StringComparison.OrdinalIgnoreCase))
        {
            string s2 = s.Replace("CREATE ", "ALTER ", StringComparison.OrdinalIgnoreCase);
            script.AppendLine(s2);
        }
        else
        {
            script.AppendLine(s);
        }

        // it's a hack because scripting of the "GO" not working well
        if (s == "SET ANSI_NULLS ON" || s == "SET QUOTED_IDENTIFIER ON")
            script.AppendLine("GO");
    }

    script.AppendLine("GO");

    string fileName = schema + "." + name + ".sql";
    await File.WriteAllTextAsync(folder + "\\" + fileName, script.ToString());
}

readonly static ScriptingOptions scriptOptionsCreate = new ScriptingOptions()
{
    //WithDependencies = true,  // will add create table before create view
    IncludeHeaders = false,  /****** Object:  View [dbo].[v_people]    Script Date: 9/30/2021 6:03:10 PM ******/
    ScriptSchema = true,
    ScriptData = false,
    Indexes = true,
    ClusteredIndexes = true,
    FullTextIndexes = true,

    // GO attempt
    FileName = "test.sql",
    ScriptBatchTerminator = true,
    NoCommandTerminator = false,
    //ToFileOnly = true,  // it makes script empty
    AppendToFile = true,
    EnforceScriptingOptions = true,
    AllowSystemObjects = true,
    Permissions = true,
    DriAllConstraints = true,
    SchemaQualify = true,
    AnsiFile = true,
    //AnsiPadding = false,
};

完全に機能するアプリはこちらです: https ://github.com/sam-klok/CreateSQLScriptsFromDB/blob/main/CreateSQLScriptsFromDB/Program.cs

于 2021-10-01T23:19:21.480 に答える