データベースを右クリックして、[タスク]メニューの[スクリプトの生成]から手動でスクリプトを生成しました。
今私の問題は、c#コードを介してそのスクリプトを生成することです...
私の質問は
C#コードを介して生成することは可能ですか?
完了するためのヒントを教えてください。
あなたの貴重な提案とコマンドを待っています。
データベースを右クリックして、[タスク]メニューの[スクリプトの生成]から手動でスクリプトを生成しました。
今私の問題は、c#コードを介してそのスクリプトを生成することです...
私の質問は
C#コードを介して生成することは可能ですか?
完了するためのヒントを教えてください。
あなたの貴重な提案とコマンドを待っています。
すでに述べたように、これを行うには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();
}
このリンクは、ストアドプロシージャの取得とスクリプト作成に役立つ場合があります
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): $_"
}
}
@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);
}
私は上記の回答を使用して、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);
オプション
そこから、必要な出力を再作成するために設定するオプションを理解する必要があります。覚えておくべきいくつかのこと:
外部キーなどを取り出す方法の詳細については、この投稿を参照してください。
健康警告
バックアップと復元では望みどおりの結果が得られないと思ったので、データベースをコピーする方法としてこれを検討し始めました。smoパスをかなり長い道のりをたどり、多くの問題に遭遇した後、私は少し再評価を行い、そのユースケースではバックアップと復元がはるかに簡単であることがわかりました。
うまくいけば、それはあなたと今後の人たちを導くでしょう。
次の必要な名前空間を含めるには、プロジェクトに次の4つの参照を追加する必要があります
参照を追加するには
名前空間
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が見つかりませんでしたが、上記のコードでも解決されています。
ストアドプロシージャのスクリプトを取得する例。注:文字列操作で「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