SQL Server 使用C#窗体与数据库连接,制作数据库查看器

本文中心:讨论C#对SQL Server 的增删改查,使用Treeview制作数据库查看器。

  • SSMS部分:确保SQL Server 提供 SQL身份验证,同时建立一个对 名为 test 的数据库有操作权限的用户(用户名:pc,密码:123456)
--建表,插入数据
use test;

create table [User_Info](
	[ID] int not null primary key,
	[Username] varchar(20) not null,
	[Password] varchar(10) not null
);

create table [Blog](
	[ID] int not null primary key check([ID]>0),
	[Title] varchar(100) not null,
	[Content] varchar(100),
	[Author_Id] int references [User_Info]([ID])
);

insert into [User_Info] values(001,'Kevin Li','123456');
insert into [User_Info] values(002,'Donold','123456');
insert into [User_Info] values(003,'Ki','123456');
insert into [User_Info] values(004,'Steves','123456');
insert into [User_Info] values(005,'Bill','123456');
insert into [User_Info] values(006,'Jaf','123456');
insert into [User_Info] values(007,'An Li','123456');

insert into [Blog] values(01,'Build Your Dreams','Read and Action',005);

select * from User_Info;
select * from Blog;

Sql server 开窗 sql server 窗体_Text

  • C#部分:VS2022新建一个窗体应用,项目名称:”SQLServerConnection“

Sql server 开窗 sql server 窗体_System_02

  • V层:主窗体Form1布局以及修改属性如下:
  • form1
  • 事件 Load=Form1_Load
  • 属性 StartPosition=CenterScreen
  • 属性 FormBorderStyle = FixedSingle
  • 属性 Text = SQLServer数据库查看器
  • 属性 MaximizeBox = False
  • treeView1
  • 事件 AfterSelect = treeView1_AfterSelect
  • listView1
  • 属性 FullRowSelect = True
  • 属性 GridLines = True
  • 属性 View = Details

Sql server 开窗 sql server 窗体_Sql server 开窗_03

  • M层:新建数据库连接类 DB.cs
    相当于M层的角色,采用了单例的思想编写,确保数据库不会被多次连接占用系统的资源.C#对SQL Server的查询过程为:先打开数据库,查询,关闭数据库连接。只是查出来的结果,C#直接放到 **SqlDataAdapter **中,再直接 Fill 方法填充到 DataTable 里面。
    这里主要提供两个方法,一是 getBySql 提供查询使用,即从SQL Server 查询数据使用;二是 setBySql 用作写数据。上述两个方法提供不同参数的重载,主要是用于应对带参数与不带参数的查询。
    这里采用 string.format("{0}{1}",new Object[]{"a","b"});将a,b分别替换{0}与{1}的位置,防止任何形式的SQL注入。如补加 and 1 or 1在后面最后会形成 where xx = 'and 1 or 1'。
    同时由于C#规定不能在构造函数中关闭连接,这里只能实现 IDisposable 的接口。
    在本程序中没用到写。
using System;
using System.Collections.Generic;
using System.Data;  //DataTable 用到
using System.Data.SqlClient;    //一系列的数据库操作类用到
using System.Text;

namespace SQLServerConnection
{
    class DB : IDisposable
    {
        private SqlConnection sqlConnection;

        //以下代码保证该类只能有一个实例
        //在自己内部定义自己的一个实例,只供内部调用
        private static DB db = null;

        //这个类必须自动向整个系统提供这个实例对象
        //这里提供一个供外部访问本class 的静态方法,可以直接访问
        public static DB GetInstance()
        {
            if (db == null)
            {
                db = new DB();
            }
            return db;
        }

        //私有无参构造函数
        public DB()
        {
            sqlConnection = new SqlConnection("server=.;uid=pc;pwd=123456;database=test");
            sqlConnection.Open();
        }

        //单例化结束

        //查询
        public DataTable GetBySql(String sql, Object[] param)
        {
            sql = String.Format(sql, param);//用字符串参数替换的形式防止注入
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(new SqlCommand(sql, sqlConnection));
            DataTable dataTable = new DataTable();
            sqlDataAdapter.Fill(dataTable);
            return dataTable;
        }

        //无参数的查询
        public DataTable GetBySql(String sql)
        {
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(new SqlCommand(sql, sqlConnection));
            DataTable dataTable = new DataTable();
            sqlDataAdapter.Fill(dataTable);
            return dataTable;
        }

        //无查询结果的修改
        public void setBySql(string sql, Object[] param)
        {
            sql = String.Format(sql, param);//用字符串参数替换的形式防止注入
            new SqlCommand(sql, sqlConnection).ExecuteNonQuery();
        }

        //无参数,无查询结果的修改
        public void setBySql(string sql)
        {
            new SqlCommand(sql, sqlConnection).ExecuteNonQuery();
        }

        //相当于析构函数
        public void Dispose()
        {
            sqlConnection.Close();
            //在C#中关闭数据库连接不能在类的析构函数中关闭,否则会抛出“内部.NET Framework 数据提供程序错误 1”的异常
            //通过实现C#中 IDisposable 接口中的 Dispose() 方法主要用途是释放非托管资源
        }
    }
}
  • C层:Form1.cs,承担将数据库的查询结果与其他组件连接起来的角色。主要使用了TreeView,对其节点TreeNode的操作,节点名同样是Text,在节点下添加节点用父节点Nodes.Add(子节点)。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;


namespace SQLServerConnection
{
    public partial class Form1 : Form
    {
        DB db;
        public Form1()
        {
            InitializeComponent();
        }
        //选择树节点触发
        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //删除根节点,点击根节点是没有任何动作的!
            if (e.Node.Parent != null)
            {
                string table_name = e.Node.Text;
                groupBox2.Text = "表" + table_name;
                listView1.Clear();
                //查表的信息
                DataTable table_info = db.GetBySql("select name from syscolumns where id=object_id('{0}')", new Object[] { table_name });
                for (int i = 0; i < table_info.Rows.Count; i++)
                {
                    for (int j = 0; j < table_info.Columns.Count; j++)
                    {   //生成表头
                        listView1.Columns.Add(table_info.Rows[i][j] + "", listView1.Width / table_info.Rows.Count - 1, HorizontalAlignment.Left);
                    }
                }
                //查表的内容
                DataTable table = db.GetBySql("select * from [{0}]", new Object[] { table_name });
                //数据更新,UI暂时挂起,知道EndUpdate绘制控件,可以有效避免闪烁并大大提高加载速度
                listView1.BeginUpdate();
                for (int i = 0; i < table.Rows.Count; i++)
                {
                    ListViewItem listViewItem = new ListViewItem();//生成每一列
                    for (int j = 0; j < table.Columns.Count; j++)
                    {
                        if (j <= 0)
                        {
                            listViewItem.Text = table.Rows[i][j] + "";
                        }
                        else
                        {
                            listViewItem.SubItems.Add(table.Rows[i][j] + "");
                        }
                    }
                    listView1.Items.Add(listViewItem);
                }
                //结束数据处理,UI界面一次性绘制。
                listView1.EndUpdate();
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                TreeNode root_node = new TreeNode();//建立节点
                root_node.Text = "Test 数据库";
                treeView1.Nodes.Add(root_node);
                db = DB.GetInstance();//初始化数据库查询单例 DB.cs
                //查询test数据库有多少张表
                DataTable table_name = db.GetBySql("select name from sysobjects where(xtype = 'U')");
                //遍历查询出来的结果表(视图)
                for (int i = 0; i < table_name.Rows.Count; i++)
                {
                    for (int j = 0; j < table_name.Columns.Count; j++)
                    {
                        TreeNode treeNode = new TreeNode();
                        treeNode.Text = table_name.Rows[i][j] + "";
                        //一一将查询结果也就是表名添加到树节点
                        root_node.Nodes.Add(treeNode);
                    }
                }
            }
            catch
            {
                MessageBox.Show(this.Text, "数据库出错!");
                Environment.Exit(1);
            }
        }
    }
}
  • 效果

Sql server 开窗 sql server 窗体_Sql server 开窗_04

解决方案含有的目录:

DB.cs 是数据库连接类

Form1.cs 是主窗体

Sql server 开窗 sql server 窗体_Text_05