简单的 SQL Server 工具 (C#)






4.61/5 (33投票s)
在本文中,我们将了解如何创建一个简易的 SQL Server 工具。
引言
*请观看我的 Youtube 视频链接,学习我使用 C# 的简易 SQL SERVER 工具。
简易 SQL Server 工具将允许用户创建 SQL Server 数据库、删除数据库、从选定的 SQL Server 加载所有数据库名称、创建新表、向表中插入记录、从表中选择记录并将结果绑定到网格、将选定结果导出为 CSV 文件格式、删除表、删除表中所有记录,而无需编写任何 SQL 脚本。
我们使用 SQL Server Management Objects (SMO) 来以编程方式创建 SQL Server 数据库、表等。
什么是 SQL Server Management Objects (SMO)?
SQL Server Management Objects (SMO) 是一组用于以编程方式管理 SQL Server 的对象。使用 SMO 对象,我们可以以编程方式连接到 SQL Server,获取所有数据库名称的集合,创建新数据库,备份数据库,还原数据库,创建表,获取给定数据库的表名称集合,获取给定表的全部列详细信息等等。
参考网站:要了解有关 SQL Server SMO 的更多详细信息,请查看所有这些链接
Shanu 简易 SQL Server 工具 (SESST) 中的功能
- 连接到 SQL Server
- 表详细信息
- SQL 脚本选项卡(创建表选项卡 / 插入和删除记录选项卡 / 选择查询选项卡)
- 输出窗口
在这里,我们将看到每个部分的详细信息。
步骤 1:连接到 SQL Server
SQL Server 连接
我们可以连接到我们网络中的任何 SQL Server。我们需要提供 SQL Server 名称或 IP 地址、SQL Server 登录 ID 和密码来连接到 SQL Server。
创建新数据库
检查用户输入的数据库名称是否存在于 SQL Server 中。如果存在,则向用户显示消息。如果不存在用户输入的名称的数据库,则将创建新数据库。
加载数据库
将所有数据库名称加载到 combobox
中,用于创建表。
删除数据库
用户可以从 SQL Server 中删除选定的数据库。删除之前,将向用户显示确认框,询问是否删除。如果用户单击“确定”,则将删除选定的数据库。
数据库备份
将选定的数据库备份到您选择的任何文件夹。
数据库恢复
用户可以通过选择所选文件夹中的“.bak”文件来恢复数据库。
步骤 2:表详细信息
加载表
用户需要先选择数据库,然后才能列出所有表名。选择数据库并单击“加载表名”后,所有表名将加载到 Combobox
中。
删除表
用户可以从 SQL Server 中删除选定的表。删除之前,将向用户显示确认框,询问是否删除。如果用户单击“确定”,则将删除选定的表。
步骤 3:SQL 脚本选项卡
在这里,我们将有三个选项卡,第一个选项卡用于创建表,第二个选项卡用于插入和删除记录,第三个选项卡用于选择查询。我们将在此处查看所有三个选项卡的详细信息。
创建表选项卡
在这里,用户无需编写 SQL 查询即可创建自己的表。首先,用户需要选择需要创建表的数据库。选择数据库后,用户可以在文本框中输入其 SQL 表名。输入表名后,用户需要为该表添加列。没有添加列,就无法创建表。
添加列
用户可以添加列来创建新表。所有这些列将本地添加到网格中,以便最终创建表。用户可以添加任意数量的列,删除选定的列,还可以通过单击 **清除列** 来删除所有列。添加和删除列不与数据库交互,因此这是一个临时位置,用于添加用于创建表的列。在为表添加所有列后,用户可以单击 **创建表** 按钮来创建具有给定列详细信息的新表。
数据类型
现在,这里只使用了三种 datatype
Int
(数字)varchar
(文本)nVarchar
(数字和文本)
用户还可以添加每个列数据的大小。对于整数,大小将不被使用,但对于 Varchar
和 nVarchar
数据类型,用户可以添加列数据大小。用户还可以通过选择 **最大大小** 复选框来为 Varchar
和 nVarchar
类型设置 Max
大小。
例如,我们可以看到下图。这里我们在网格中添加了四个列,并添加了一个新列,我们可以从网格中看到每个列的 Datatype
和 Size
。添加完所有列后,我们单击 **创建表** 按钮。我们可以看到确认消息“Table
已创建”,并且我们还可以看到我们的新 Table
已添加到 Table List Combobox
中。
插入和删除记录选项卡
我们将使用最近创建的测试表进行插入演示。
在这里,我们可以看到上图,我们从表列表中选择了表“test
”。要向选定的 Table
插入记录,我们需要单击 **加载表详细信息以进行插入** 按钮。单击此按钮后,我们将显示所有列名和 textbox
。根据每个列的 Datatype
,我们将添加带有 maxlength
的 textbox
。如果列 datatype
是 Integer
,那么我们将为该列添加 Numeric textbox
,这样用户只能在该 textbox
中输入数字。对于 Varchar
和 nVarchar
,我们将检查每个列的大小,如果它是 max,那么我们将 textbox maxlength
设置为 200
;这样用户最多只能输入 200 个字符。如果为列设置了大小,那么我们将列大小设置为 textbox maxlength
。
Insert
在加载所有带有 TextBox
的列详细信息后,用户可以输入要插入的值。一旦用户输入了值,单击 **插入到选定表中** 按钮即可插入新记录。类似地,用户可以为选定的表输入任意数量的记录。如果您想从代码中添加更多功能,可以添加自己的功能,例如在插入之前检查重复值等。
删除所有记录
用户可以删除选定表的所有记录。在此示例中,我们不检查删除记录的任何条件。如果您需要添加更多功能,可以从代码中进行更改并添加自己的函数,例如根据条件删除表的记录等。
选择查询选项卡
为了从数据库中选择记录并显示结果,用户首先需要选择数据库,然后从表列表中选择表来创建 SQL Select
查询。
用户可以通过三种功能选择详细信息
- 所有列:如果选中“所有列”复选框,则所有列的详细结果将显示在输出窗口网格中。(这与
select
查询中的*
相同,例如select * from tablename
)。从上图可以看出,“所有列”复选框默认加载。选择表后,当用户单击“运行选择查询”时,所有列详细信息将加载到以下输出窗口网格中。 - 用户选定的列:如果用户只想显示表的特定列,那么他们可以单击“加载表列以进行 **选择**”按钮,将所有表列名显示到
CheckedListbox
中。在这里,用户可以选择他们需要的列,并且默认选中所有列名。用户可以取消选中不需要的列,也可以取消选中“所有列”复选框以仅显示选定的列作为结果。 - 用户可以编写 SQL Select 查询:用户还可以编写他们的 SQL Select 查询来显示输出。
例如,如果用户想编写自己的 SQL 查询来连接 3 个表并显示结果。要编写 SQL Select 查询,用户需要选中 **SQL Select Query** 复选框,并在编写 select 查询后,用户可以单击 **Run Select Query** 按钮来查看结果。在上图中,我们可以看到我们编写了一个示例 SQL Join
查询来连接三个表,并通过单击 **Run Select** 查询,结果已绑定到网格中。
用户输入的 Select 查询中的 SQL 注入检查
在执行用户输入的 SQL Select 查询之前,我们还检查了 SQL 注入。我们创建了一个 ArrayList 来添加所有 SQL 注入字符串,并且我们将检查数组中的任何单词是否与用户输入的 select
查询匹配。例如,我们可以看到上图,在 select
查询之后,我们输入了 drop
查询。但是当我们单击 **Run Select Query** 按钮时,我们将显示消息“drop
在 select
查询中不被接受”。
这是我正在检查的 SQL 注入字符串列表。如果需要,您可以根据您的要求添加或删除。
string[] sqlInjectionArray = { "create", "drop", "delete",
"insert", "update", "truncate","grant ","print",
"sp_executesql ,"objects","declare","table","into",
"sqlcancel","sqlsetprop","sqlexec","sqlcommit","revoke",
"rollback","sqlrollback","values","sqldisconnect",
"sqlconnect","user","system_user","use","schema_name",
"schemata","information_schema","dbo","guest","db_owner",
"db_","table","@@","Users","execute","sysname",
"sp_who","sysobjects","sp_","sysprocesses ","master",
"sys","db_","is_","exec", "end", "xp_",
"; --", "/*", "*/", "alter", "begin", "cursor",
"kill","--" ,"tabname","or","sys"};
保存 Select 查询
用户还可以将 Select 查询另存为文本文件到选定的文件夹,以便以后使用该 select 查询。
打开已保存的 Select 查询
用户还可以打开已保存的 Select 查询来执行 select 脚本。
将结果导出为 CSV 文件格式
用户还可以将选定的结果导出为 CSV 格式。在这里,下图显示了结果已导出为 CSV 文件。
必备组件
SQL Server SMO 参考:为了使用 SQL Server SMO,我们需要为我们的项目添加四个重要的引用。
- Microsoft.SqlServer.ConnectionInfo.dll
- Microsoft.SqlServer.Smo.dll
- Microsoft.SqlServer.Management.Sdk.Sfc.dll
- Microsoft.SqlServer.SqlEnum.dll
您可以在此路径找到引用(这里我们使用了 SQL Server 2014)。
C:\Program Files\Microsoft SQL Server\120\SDK\Assemblies\
将这四项程序集引用添加到您的项目中
Using the Code
主要目标是创建一个简单易用的简易 SQL 工具。所有功能都已添加在一个带有选项卡的主窗体中。我们创建了两个类
smoSQLServerClass
:在此类中,我们创建了连接、断开 SQL Server、创建数据库、删除数据库、备份数据库、将所有异常写入可执行文件夹中的日志文本文件、创建表等的函数。sqlBizClass
:在此类中,我们执行所有业务逻辑,用于我们的主窗体,例如创建动态查询、创建动态控件并绑定到面板、将从SMOSQLServerClass
返回的所有表名绑定到Combobox
控件、为Select
查询检查 SQL 注入并以true
或false
返回结果等。
在这里,我们将看到简易 SQL Server 工具中使用的一些重要代码部分。所有代码部分都已添加了详细的注释,因此用户可以轻松理解代码。
连接到 SQL Server
在本文中,我提到了使用 SQL Server SMO 对象,我们需要为我们的项目添加四个重要的程序集引用。使用 SMO ServerConnection
,我们可以连接到 SQL Server。我们需要将 SQL Server 名称设置为 ServerInstance
,并设置 SQL Server 登录名和密码。连接后,我们检查连接是否打开,并将布尔值返回到我们的 main
函数,以向用户显示适当的消息。
public bool SqlServerConnect()
{
try
{
servConn = new ServerConnection();
servConn.ServerInstance = serverName;
servConn.LoginSecure = false;
servConn.Login = LoginID;
servConn.Password = password;
servConn.Connect();
if(servConn.IsOpen)
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
writeLogMessage(ex.Message.ToString());
}
return false;
}
将异常消息写入日志文件
我们将把所有异常错误消息写入日志文件,并包含 Date
和 Time
。
public void writeLogMessage(String logMessage)
{
string path = Application.StartupPath + @"\LogFile.txt";
logMessage = logMessage + " - on " + DateTime.Now.ToString();
if (!File.Exists(path))
{
using (StreamWriter tw = File.CreateText(path))
{
tw.WriteLine(logMessage);
tw.Close();
}
}
else
{
StreamWriter tr = new StreamWriter(path);
tr.WriteLine(logMessage);
tr.Close();
}
}
加载数据库名称
在“加载数据库名称”按钮的单击事件中,我们将 comboBox
控件传递给 Biz
类方法。在 biz
类方法中,我们将调用 SMO
类来获取所有数据库名称,并将所有数据库名称添加到 combobox
。在此方法中,我将检查 Master 数据库,出于安全原因将不添加其名称,例如,用户可以从我们的主窗体中删除数据库。类似地,您可以更改代码以限制任何数据库在我们的主窗体中显示。
public void loaddbNames(ComboBox cbo)
{
//return objSQL.loaddbNames();
DatabaseCollection dbnamesCol = objSQL.loaddbNames();
cbo.Items.Clear();
cbo.Items.Add("");
if (dbnamesCol != null)
{
string dbnames = "";
int ival = 0;
foreach (Database db in dbnamesCol)
{
if (db.Name != "master")
{
cbo.Items.Add(db.Name);
} }
}
cbo.SelectedIndex = 0;
}
在 SMO 类中,我们将加载给定 SQL Server 的所有数据库名称,并作为 DatabaseCollection
返回给调用类。
public DatabaseCollection loaddbNames()
{
DatabaseCollection dbNames = null;
try
{
if (SqlServerConnect())
{
Server srv = new Server(servConn);
dbNames = srv.Databases;
SqlServerDisconnect();
}
}
catch (Exception ex)
{
writeLogMessage(ex.Message.ToString());
}
return dbNames;
}
创建数据库
在此函数中,我们首先检查用户输入的名称是否已存在数据库。如果 SQL Server 中不存在同名数据库,我们将创建一个新数据库。如果 SQL Server 中已存在数据库,则返回“数据库已存在”的消息。
public string createourDatabase(string DatabaseName)
{
try
{
if (SqlServerConnect())
{
Server srv = new Server(servConn);
Database database = srv.Databases[DatabaseName];
if (database == null)
{
database = new Database(srv, DatabaseName);
database.Create();
database.Refresh();
SqlServerDisconnect();
return "Database Created Successfully !";
}
else
{
SqlServerDisconnect();
return "Database Already Exist";
}
}
else
{
return "Enter valid SQL Connection Details";
}
}
catch (Exception ex)
{
writeLogMessage(ex.Message.ToString());
}
return "Sorry Error While creating DB";
}
创建表
在创建按钮的单击时,我们将用户选择的数据库名称、用户输入的表名以及作为 DataTable 的列详细信息传递给 SMO 类。在此函数中,我们将检查表是否已存在;如果存在,则向用户返回 false 消息,否则,我们将创建一个带有列详细信息的新表。
public string createTable(string DatabaseName, string TableName,DataTable dtColumns)
{
try
{
if (SqlServerConnect())
{
Server srv = new Server(servConn);
Database database = srv.Databases[DatabaseName];
if (database != null)
{
bool tableExists = database.Tables.Contains(TableName);
if (tableExists)
{
SqlServerDisconnect();
return "Table Already Exist.kindly Enter Different Table Name";
}
else
{
Table tbl = new Table(database, TableName);
foreach (DataRow dr in dtColumns.Rows)
{
string columnName = dr["ColumName"].ToString();
string DataType = dr["DataType"].ToString();
string dataSize = dr["Size"].ToString();
Microsoft.SqlServer.Management.Smo.Column columntoAdd =null;
switch (DataType)
{
case "Varchar":
if(dataSize=="max")
{
columntoAdd = new Column(tbl, columnName,
Microsoft.SqlServer.Management.Smo.
DataType.VarCharMax);
}
else if (dataSize != "")
{
columntoAdd = new Column(tbl, columnName,
Microsoft.SqlServer.Management.Smo.
DataType.VarChar(Convert.ToInt32(dataSize)));
}
break;
case "Int":
columntoAdd = new Column(tbl, columnName,
Microsoft.SqlServer.Management.Smo.DataType.Int);
break;
case "nVarchar":
if (dataSize == "max")
{
columntoAdd = new Column(tbl, columnName,
Microsoft.SqlServer.Management.Smo.
DataType.NVarCharMax);
}
else if (dataSize != "")
{
columntoAdd = new Column(tbl, columnName,
Microsoft.SqlServer.Management.Smo.
DataType.NVarChar(Convert.ToInt32(dataSize)));
}
break;
}
if(columntoAdd!=null)
{
tbl.Columns.Add(columntoAdd);
}
}
tbl.Create();
SqlServerDisconnect();
return "Table Created Successfully !";
}
}
}
else
{
return "Enter valid SQL Connection Details";
}
}
catch (Exception ex)
{
writeLogMessage(ex.Message.ToString());
}
return "Sorry Error While Creating Table";
}
加载用于插入的列详细信息
在“加载列详细信息”按钮的单击时,我们将 Panel 控件传递给我们的 biz
类,以获取选定表的所有列详细信息,并将带有列名的文本框绑定到面板。从我们的 SMO 类,我们将获取表的所有列详细信息,并将其作为 ColumnCollection
返回。在 biz
类中,使用 foreach
,我们将所有列详细信息添加为 Label
控件来显示列名,并添加一个 Textbox
用于用户输入。在此方法中,我们将检查列类型和列大小。如果列类型是 Integer
,那么我们将 Textbox
设置为 Numeric Textbox
。如果列类型是 Varchar
或 NVarchar
,我们检查列长度并将其长度指定为 TextBox Maxlength
。
public void loadTableColumnDetails(Panel pnControls, string DataBaseName,string TableName)
{
ColumnCollection tableColumnDetail =
objSQL.loadTableColumnDetails(DataBaseName, TableName);
pnControls.Controls.Clear();
if (tableColumnDetail != null)
{
string dbnames = "";
int lableHeight = 20;
int textboxHeight = 20;
int lablewidth = 100;
int lableXVal = 10;
int lableYVal = 10;
foreach (Column colName in tableColumnDetail)
{
string s = colName.Name;
Random rnd = new Random();
int randNumber = rnd.Next(1, 1000);
//to add Column name to display as caption
Label ctrl = new Label();
ctrl.Location = new Point(lableXVal , lableYVal+6);
ctrl.Size = new Size(lablewidth , lableHeight);
ctrl.Name = "lbl_" + randNumber; ;
ctrl.Font = new System.Drawing.Font("NativePrinterFontA", 7F,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
ctrl.Text = colName.Name;
pnControls.Controls.Add(ctrl);
//to add textbox for user enter insert text
TextBox ctrltxt = new TextBox();
ctrltxt.Location = new Point(lableXVal+110, lableYVal);
ctrltxt.Size = new Size(lablewidth+40, lableHeight);
ctrltxt.Name = "txt_" + randNumber;
ctrltxt.Font = new System.Drawing.Font("NativePrinterFontA", 8F,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
ctrltxt.Text = "";
if (colName.DataType.Name== "int")
{
ctrltxt.MaxLength = 20;
ctrltxt.KeyPress += new KeyPressEventHandler(textBox_KeyPress);
}
else
{
if(colName.DataType.MaximumLength.ToString()!="-1")
{
ctrltxt.MaxLength =
Convert.ToInt32(colName.DataType.MaximumLength.ToString());
}
else
{
ctrltxt.MaxLength =100;
}
}
pnControls.Controls.Add(ctrltxt);
//to add Column datatype as hidden field
Label ctrllbl = new Label();
ctrllbl.Location = new Point(lableXVal + 112, lableYVal + 6);
ctrllbl.Size = new Size(1, 1);
ctrllbl.Name = "_lblDT_" + randNumber; ;
ctrllbl.Font = new System.Drawing.Font("NativePrinterFontA",
7F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((byte)(0)));
ctrllbl.Text = colName.DataType.Name;
ctrllbl.Visible = false;
pnControls.Controls.Add(ctrllbl);
if (lableXVal + 360 < pnControls.Width-110)
{
lableXVal = lableXVal + 270;
}
else
{
lableXVal = 10;
lableYVal = lableYVal + 40;
}
}
}
}
//for numeric textbox validation
private void textBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
在 SMO 类 loadTableColumnDetails
方法中,我们将获取给定数据库和表名的所有列详细信息,并将列详细信息作为 ColumnCollection
返回给 biz
类,以便为用户输入动态控件添加以插入记录。
public ColumnCollection loadTableColumnDetails(string DatabaseName,string TableName)
{
ColumnCollection columnDetails = null;
try
{
if (SqlServerConnect())
{
Server srv = new Server(servConn);
Database db = srv.Databases[DatabaseName];
bool tableExists = db.Tables.Contains(TableName);
if (tableExists)
{
foreach (Table table in db.Tables)
{
if (table.Name == TableName)
{
columnDetails = table.Columns;
break;
}
}
}
SqlServerDisconnect();
}
}
catch (Exception ex)
{
writeLogMessage(ex.Message.ToString());
}
return columnDetails;
}
插入记录
在插入按钮的单击时,我们将用户添加的插入详细信息面板控件与数据库名称和表名传递给 biz
类。在 biz
类中,我们将创建一个动态插入查询,添加所有列名,并将所有插入值作为参数,然后将 SqlCommand
传递给 SMO
类 insertQuery
方法,以将新记录插入到给定的表中。
public string saveTableInsertQuery(Panel pnControls, string DataBaseName, string TableName)
{
string result = "";
StringBuilder sqlQuery = new StringBuilder("INSERT INTO " + TableName );
StringBuilder Insert = new StringBuilder(" (");
StringBuilder values = new StringBuilder("VALUES (");
SortedDictionary<string, string> sd = new SortedDictionary<string, string>();
string columnName = "";
string colvalue = "";
string dataType = "";
int iCount = 0;
SqlCommand command = new SqlCommand();
foreach (Control p in pnControls.Controls)
{
if (p.Name.ToString().Substring(0, 4) == "lbl_")
{
columnName = p.Text;
}
else if (p.Name.ToString().Substring(0, 4) == "txt_")
{
colvalue = p.Text;
}
else if (p.Name.ToString().Substring(0, 4) == "_lbl")
{
Insert.Append(columnName);
Insert.Append(", ");
sd.Add(columnName, colvalue);
values.Append("@" + columnName);
values.Append(", ");
if (p.Text == "int")
{
command.Parameters.Add("@" + columnName,
SqlDbType.Int).Value = colvalue;
}
else if (p.Text == "varchar")
{
command.Parameters.Add("@" + columnName,
SqlDbType.VarChar).Value = colvalue;
}
else if (p.Text == "nvarchar")
{
command.Parameters.Add("@" + columnName,
SqlDbType.NVarChar).Value = colvalue;
}
}
}
string sqlresult = Insert.ToString().Remove(Insert.Length - 2) + ") ";
sqlQuery.Append(sqlresult);
string valueresult = values.ToString().Remove(values.Length - 2) + ") ";
sqlQuery.Append(valueresult);
sqlQuery.Append(";");
command.CommandText = sqlQuery.ToString();
command.CommandType = CommandType.Text;
return objSQL.insertQuery(DataBaseName, sqlQuery.ToString(), command);
}
选择查询
在选择按钮的单击时,我们检查选择查询类型,如果 SQL Select Query 复选框未选中,那么我们将所有列详细信息传递给 biz
类 selectRecordsfromTableQuery
方法来创建动态 SQL Select
查询。如果用户选择了所有列,那么我们将使用“select * from tablename
”。如果用户只选择了少数几列显示,那么我们将创建一个动态查询并添加用户选择的所有列,然后将结果作为 DataTable
返回以绑定到网格中。
public DataTable selectRecordsfromTableQuery
(bool isAllColumns, CheckedListBox chkListBoxCols, string DataBaseName, string TableName)
{
string result = "";
StringBuilder sqlQuery = new StringBuilder("Select * FROM " + TableName);
string sqlresult = sqlQuery.ToString();
if (!isAllColumns)
{
sqlQuery = new StringBuilder("Select " );
foreach (object itemChecked in chkListBoxCols.CheckedItems)
{
string colsName = itemChecked.ToString();
sqlQuery.Append(colsName+", ");
}
sqlresult = sqlQuery.ToString().Remove(sqlQuery.Length - 2) +
" FROM " + TableName;
}
SqlCommand command = new SqlCommand();
command.CommandText = sqlresult;
command.CommandType = CommandType.Text;
return objSQL.selectRecordsfromTableQuery(DataBaseName, command);
}
关注点
希望大家喜欢这篇文章。无需编写 SQL 脚本,现在会员可以连接到 SQL Server,创建数据库、表、插入和选择记录。此工具目前存在一些限制,例如我们现在只能添加三种数据类型等。对我们的期望没有限制,现在代码和工具就在您的手中,您可以根据您的需求添加任意数量的功能。
历史
- 2016 年 1 月 5 日:初始版本