【C#】利用C#窗体与SQL Server的连接、Treeview制作SQL Server数据库查看器

实质上,本文的中心还是在讨论C#对SQL Server的增删改查,只是这次创新一点,配合Treeview制作SQL Server数据库查看器。

具体如下图:

根据SQL Server,Test数据库中的表的结构与内容:


编写一个对Test数据库的数据库查看器,点击相应的表则读取该表的内容:


其中上述的程序,点击根节点“Test数据库”是无效的,点击其子节点,则右方的组框改成相应的表名,

同时读出此表的内容。

在制作之前,请根据《【SQL Server】用户的设置与授权、sa用户登录、查询一个数据库中有多少张表》(点击打开链接)确保你的SQL Server以提供SQL身份验证,同时开一个对test拥有数据库操作权限的用户名pc与密码为admin的账户,否则下述不通过数据库路径连接SQL Server的方式可能会无效。

1、首先,解决方案含有的目录示意图如下所示:


其中DB.cs是我自己编写的数据库连接类,相当于M层的角色,采用了《【Java】利用单例模式、可变参数优化Java操作Mysql数据库、JDBC代码的写作》(点击打开链接)中单例的思想编写,确保数据库不会被多次连接占用系统的资源。具体代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;//DataTable用到
using System.Data.SqlClient;//一系列的数据库操作类用到

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;
        }

        private DB()// 私有无参构造函数
        {
            sqlConnection = new SqlConnection("server=.\\SQLEXPRESS;uid=pc;pwd=admin;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#对SQL Server的查询很简单。与其它编程语言类似,先打开数据库,查完再关闭数据库连接。

只是,查出来的结果,C#是直接放到SqlDataAdapter中,再直接Fill方法填充到DataTable里面。

这里主要提供两个方法,一个是getBysql提供查询使用,也就是从SQL Server查数据使用,对应的则是setBySql,用作写数据的,虽然这个程序在后续没有任何要向数据库写的地方,也就是没有用到方法,但你感兴趣可以继续按照《【C#】ListView的使用,对Access数据库的增删改查》(点击打开链接)的思路做下去,进一步提供增删改的功能。

上述两个方法提供不同参数的重载,主要是用于应对带参数与不带参数的查询。

这里采用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的接口了。

之后就是主窗体Form1了,布局及其所要修改的属性如下,相当于V层了:


最后是Form1.cs,相当于C层的代码,具体请看注释,承担将数据库的查询结果与其它组件连接起来的角色。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;

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 });
                listView1.BeginUpdate();//数据更新,UI暂时挂起,直到EndUpdate绘制控件,可以有效避免闪烁并大大提高加载速度  
                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);
                }
                listView1.EndUpdate();//结束数据处理,UI界面一次性绘制。  
            }
        }

        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
                DataTable table_name = db.getBySql("SELECT name FROM sysobjects WHERE (xtype = 'U')");//查询test数据库表有多少张表
                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);
            }
        }
    }
}

上述展示了TreeView的使用。主要是对其节点TreeNode的操作,节点名称同样是Text,在节点下添加节点用父节点.Nodes.Add(子节点);

而ListView的具体使用,在《【C#】ListView的使用,对Access数据库的增删改查》(点击打开链接)中讲过了,这里不再赘述了。

  • 6
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值