基于Windows C# 桌面窗体应用(.NET framework) 程序的Access学生数据库管理系统(二)---登录和注册页面之SQL查找与添加

前言

  • 本文我们将通过Windows C#的桌面应用程序来做一个学生数据库查询系统,其中学生数据库的信息是存储在Access数据库的.accdb文件中
  • 本教程包含如下内容(注:本教程只设计一些基础内容进行教学,不考虑安全性和美观以及用户体验):
    • 主界面
    • 登录界面
    • 注册界面
    • 数据库增删改查界面
  • 下面是本教程的使用到的环境,本教程不涉及如何安装环境和配置,请大家自行移步去其他教程搜寻~
    • Office 2021 Mircosoft Acess (可以考虑使用office tool plus整套替换)
    • Visual Studio 2022
  • 往期回顾:
  • 上一期我们谈论了如何使用Windows C# 桌面窗体应用程序去设计我们整个学生数据库管理系统的程序UI和代码框架,这一期我们来聊聊如何对Acess数据库进行连接和SQL增删改查的逻辑

1 创建Access数据库

  • 我们打开Access请添加图片描述

  • 在我们上一节的文件夹下创建一个数据库请添加图片描述

  • 让我们为学生登录界面的账户信息新建一个表取名为StudentsLogin,然后简单添加如下内容,这里我们为了测试做了一下几点

    • 字段设置
      • 学号设置为数字
      • 姓名性别设置为短文本
      • 出生日期设置为时间
    • 设置相同名字但不不同性别的,设置相同名字相同性别但是不不同级的同学
      请添加图片描述

2 数据库连接

2-1 配置VS数据库连接
  • 我们来连接Access数据库,在左上角工具栏工具找到连接到数据库请添加图片描述

  • 选择.accdb数据库文件请添加图片描述

  • 点击左下角测试连接,当出现连接成功说明成功和数据库建立连接请添加图片描述

  • 然后我们点开高级,在Provider里找到复制一下路径

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\lzh\Desktop\StudentDatasetsExplorer\StudentDatabases.accdb

请添加图片描述

  • 点击确认后我们就可以看到数据库连接成功请添加图片描述

2-2 数据库连接代码
  • 我们在项目中创建一个StudentDataBasesConnector.cs,专门负责建立数据库连接的类
  • 注意这里的connectionString需要替换为上面连接的字符串
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StudentDatasetsExplorer
{
    internal class StudentsDataBaseConnector
    {
        public void Connect2DataBase()
        {

            string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\lzh\Desktop\StudentDatasetsExplorer\StudentDatabases.accdb";

            using (OleDbConnection connection = new OleDbConnection(connectionString))
            {
                try
                {
                    connection.Open();
                    MessageBox.Show("data base connected!");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

    }
}

  • 同时我们在Program.cs中添加如下内容,进行数据库连接测试
 static void Main()
 {
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);
     StudentsDataBaseConnector studentsDataBaseConnector = new StudentsDataBaseConnector();
     studentsDataBaseConnector.Connect2DataBase();
     Application.Run(new MainForm());
 }
2-3 环境修正
  • 运行上述代码以后,我们会发现数据库连接异常,我们来解决这个问题 请添加图片描述

  • Microsoft.ACE.OLEDB.12.0 是一个用于访问Microsoft Access数据库的提供程序,它通常随Microsoft Access数据库引擎一起安装。这里我们补充下载一下Microsoft Access Database Engine

  • Microsoft Access Database Engine下载地址

  • 这里我们选择accessdatabaaseengine.exe下载请添加图片描述

  • 下载后我们会出现以下的程序请添加图片描述

  • 我们打开cmd,进入你的下载路径,输入下述指令

AccessDatabaseEngine.exe /quiet
  • 等待操作后我们重新回到程序,运行请添加图片描述

3 数据库连接类—单例模式

  • 考虑我们整个程序到需要用到同一份数据库,如果我们多次进行实例化进行多次数据的拷贝,这是一个资源容易出现溢出浪费的现象,熟悉设计模式的朋友们这时候可以就知道了,这里我们引入单例模式
  • 单例模式(Singleton Pattern)是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。单例模式通常用于管理共享资源,如数据库连接、文件系统、应用程序配置等,这些资源在应用程序的生命周期内只需要一个实例。
  • 单例模式的主要特点包括:
    1. 唯一实例:单例类确保只能创建一个实例。
    2. 全局访问点:单例类提供了一种全局访问点,通过这个访问点可以获取到该类的唯一实例。
    3. 延迟创建:单例实例通常在第一次被请求时创建,而不是在类加载时创建。这种技术称为延迟初始化。
  • 单例模式的实现通常涉及以下几个步骤:
    1. 私有构造函数:确保不能通过new关键字直接创建类的实例。
    2. 私有静态变量:用于存储类的唯一实例。
-----------------------------------------
| Singleton                           |
-----------------------------------------
| - instance: Singleton               |
-----------------------------------------
| + Singleton() [private]             |
| + getInstance(): Singleton           |
-----------------------------------------
  • 我们修改StudentDataBasesConnector.cs
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StudentDatasetsExplorer
{
    internal class StudentsDataBaseConnector
    {
        private OleDbConnection connection;
        private static StudentsDataBaseConnector instance;
        private StudentsDataBaseConnector() 
        {
            string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\lzh\Desktop\StudentDatasetsExplorer\StudentDatabases.accdb";
            connection = new OleDbConnection(connectionString);
        }
        public static StudentsDataBaseConnector GetInstance()
        {
            if (instance == null)
            {
                instance = new StudentsDataBaseConnector();
            }
            return instance;
        }
        public OleDbConnection GetStudentDataBaseConnection()
        {
            try
            {
                connection.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return connection;
        }
        protected object MemberwiseClone()
        {
            return this;
        }
    }
}
  • 如果我们要使用StudentsDataBaseConnector类:
StudentsDataBaseConnector studentsDataBaseConnector = StudentsDataBaseConnector.GetInstance();

4 SQL

4-1 介绍

请添加图片描述

  • SQL(结构化查询语言)是一种用于管理和操作关系数据库管理系统(RDBMS)的标准语言。它允许用户执行各种操作,如查询、更新、插入和删除数据库中的数据。SQL也可以用于创建和管理数据库对象,如表、视图和索引。
  • SQL的基础语法包括以下主要部分:
    1. SELECT:用于从数据库中选择数据。基本语法是SELECT column1, column2, ... FROM table_name
    2. WHERE:用于过滤记录。它后面通常跟着一个条件,只有满足条件的记录才会被选中。例如,WHERE condition
    3. INSERT INTO:用于向表中插入新记录。基本语法是INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...)
    4. UPDATE:用于更新表中的现有记录。基本语法是UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition
    5. DELETE:用于删除表中的记录。基本语法是DELETE FROM table_name WHERE condition
    6. CREATE TABLE:用于创建新表。基本语法是CREATE TABLE table_name (column1 datatype, column2 datatype, ...)
    7. ALTER TABLE:用于修改现有表的结构。例如,添加新列、删除列或修改列的数据类型。
    8. DROP TABLE:用于删除整个表,包括所有其包含的记录。
    9. JOIN:用于结合两个或多个表的行,基于这些表之间的相关列。
    10. UNION:用于合并两个或多个SELECT语句的结果集。
    11. ORDER BY:用于根据一个或多个列对结果集进行排序。
    12. GROUP BY:用于对结果集进行分组,通常与聚合函数(如COUNT、MAX、MIN、SUM、AVG)一起使用。
    13. HAVING:用于对分组后的结果进行过滤。
    14. LIKE:用于在WHERE子句中搜索列中的特定模式。
    15. IN:用于在WHERE子句中指定多个值。
    16. BETWEEN:用于在WHERE子句中指定范围。
    17. EXISTS:用于检查子查询是否返回任何记录。
    18. DISTINCT:用于返回唯一不同的值。
    19. AS:用于为表或列指定别名。
    20. INDEX:用于创建索引,以提高查询性能。
  • 这些是SQL的一些基础语法和命令,它们构成了大多数数据库操作的核心。
4-2 在Access中使用SQL
  • 在创建菜单栏里找到创建,点击查询设计请添加图片描述

  • 这里我们选择切换SQL视图 请添加图片描述

  • 输入SQL指令请添加图片描述

  • 双击查询1即出现结果请添加图片描述


5 注册页面–数据库添加

5-1 用户输入预处理
  • 我们打开RegisterForm.cs,我们需要在用户输入信息正确后进行数据库连接即可
5-1-1 确保学号是数字
  • int.TryParse 是 C# 中用于尝试将字符串转换为整数的方法。该方法原型如下:
    public static bool TryParse(string s, out int result);
    
    • s: 要转换的字符串。
    • result: 如果转换成功,将包含转换后的整数值;如果转换失败,则为 0
  • int.TryParse 方法返回一个布尔值,表示转换是否成功。如果字符串成功转换为整数,result 参数将包含该整数值,方法返回 true;如果转换失败(例如,字符串包含非数字字符或数字太大无法表示为 int),方法返回 false,并且 result 参数保持不变。
private bool AreAllFieldsFilled()
{
    if(string.IsNullOrEmpty(tbxID.Text)|| string.IsNullOrEmpty(tbxName.Text))
    {
        MessageBox.Show("请确认信息填写!");
        return false; 
    }
    if (!int.TryParse(tbxID.Text, out _))
    {
        MessageBox.Show("学号请填写数字!");
        return false;
    }
    foreach (RadioButton radioButton in gbxGender.Controls)
    {
        if (radioButton.Checked)
        {
            return true;
        }
    }
    MessageBox.Show("请选择性别!");

    return false;
}
5-1-2 确保时间为日期
  • dTimePkBirth.Value返回的数据为2024/8/22 21:05:54
  • 而这里我们需要的是时间数据,birthDate.Date获取日期部分,忽略时间
 DateTime birthDate = dTimePkBirth.Value;
 DateTime birthDateOnly = birthDate.Date; // 获取日期部分,忽略时间

5-2 数据库连接
  • 我们只需要调用单例模式的GetInstance接口即可(上面说过了)
 StudentsDataBaseConnector studentsDataBaseConnector = StudentsDataBaseConnector.GetInstance();
 OleDbConnection connection = studentsDataBaseConnector.GetStudentDataBaseConnection();

5-3 确保学号唯一—数据库搜索
  • 同时我们需要确保注册的账户是唯一的,假定学号是所有学生唯一的标识符
  • 这里我们用到这一条指令
    SELECT COUNT(*) FROM StudentsLogin WHERE 学号 = @ID
    
      • SELECT: 这是SQL查询语句的开始,用于指定要选择的操作。
    • COUNT(*): 这是一个聚合函数,用于计算选择的数据集中的记录数。*表示选择所有的记录。
    • FROM StudentsLogin: 这指定了要查询的表名,这里是StudentsLogin
    • WHERE: 这是一个条件子句,用于过滤查询结果。只有满足WHERE子句中条件的记录才会被包括在结果中。
    • 学号 = @ID: 这是WHERE子句中的条件,它指定了只有当学号字段等于@ID参数时,记录才会被计数。- SELECT: 这是SQL查询语句的开始,用于指定要选择的操作。
    • COUNT(*): 这是一个聚合函数,用于计算选择的数据集中的记录数。*表示选择所有的记录。
    • FROM StudentsLogin: 这指定了要查询的表名,这里是StudentsLogin
    • WHERE: 这是一个条件子句,用于过滤查询结果。只有满足WHERE子句中条件的记录才会被包括在结果中。
    • 学号 = @ID: 这是WHERE子句中的条件,它指定了只有当学号字段等于@ID参数时,记录才会被计数。
  • 如果存在,就输出。请添加图片描述
 // 检查学号是否已存在
 string checkIDSql = "SELECT COUNT(*) FROM StudentsLogin WHERE 学号 = @ID";
 OleDbCommand checkIDCommand = new OleDbCommand(checkIDSql, connection);
 checkIDCommand.Parameters.AddWithValue("@ID", int.Parse(ID));
 int count = (int)checkIDCommand.ExecuteScalar();

 if (count > 0)
 {
     MessageBox.Show("学号已存在,请重新输入!");
     clearInputs();
     return;
 }

5-4 注册—数据库添加
  • 我们为注册消息完成下述逻辑
    INSERT INTO StudentsLogin (学号, 姓名, 性别,出生日期) VALUES (@ID, @Name, @Gender,@BirthDate)
    
      • INSERT INTO: 这是SQL语句的开始,用于指定要执行的插入操作。
    • StudentsLogin: 这是目标表的名称,即新记录将被插入的表。
    • (学号, 姓名, 性别, 出生日期): 这指定了新记录将包含数据的列。这里的列名应该与StudentsLogin表中实际的列名相匹配。
    • VALUES (@ID, @Name, @Gender, @BirthDate): 这部分指定了要插入的值。@ID@Name@Gender@BirthDate是参数占位符,它们将在执行SQL语句时被替换为实际的值。
  • 然后我们添加参数
   command.Parameters.AddWithValue("@ID", int.Parse(ID));
   command.Parameters.AddWithValue("@Name", Name);
   command.Parameters.AddWithValue("@Gender", gender);
   command.Parameters.AddWithValue("@BirthDate", birthDateOnly);
  • 完整代码请添加图片描述
string register_data_info = $"将注册以下信息:\n学号: {ID}\n姓名: {Name}\n性别: {gender}\n出生日期: {birthDate.ToShortDateString()}";
MessageBox.Show(register_data_info);
clearInputs();

       

try
{
    // 构造SQL INSERT语句
    string sql = "INSERT INTO StudentsLogin (学号, 姓名, 性别,出生日期) VALUES (@ID, @Name, @Gender,@BirthDate)";

    // 创建OleDbCommand对象
    OleDbCommand command = new OleDbCommand(sql, connection);

    // 添加参数并赋值
    command.Parameters.AddWithValue("@ID", int.Parse(ID));
    command.Parameters.AddWithValue("@Name", Name);
    command.Parameters.AddWithValue("@Gender", gender);
    command.Parameters.AddWithValue("@BirthDate", birthDateOnly);
         

    // 执行SQL语句
    command.ExecuteNonQuery();

    MessageBox.Show("注册成功!");
}
catch (Exception ex)
{
    // 处理异常
    MessageBox.Show($"注册失败: {ex.Message}");
}
finally
{
    // 关闭数据库连接
    if (connection.State == ConnectionState.Open)
    {
        connection.Close();
    }
}

5-5 注册页面完整代码
  • RegisterForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Data.OleDb;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StudentDatasetsExplorer
{
    public partial class RegisterForm : Form
    {
        
        public RegisterForm()
        {
            InitializeComponent();
        }
        private void clearInputs()
        {
            tbxID.Clear();
            tbxName.Clear();
            foreach (RadioButton radioButton in gbxGender.Controls)
            {
                radioButton.Checked = false;
            }

        }
        private bool AreAllFieldsFilled()
        {
            if(string.IsNullOrEmpty(tbxID.Text)|| string.IsNullOrEmpty(tbxName.Text))
            {
                MessageBox.Show("请确认信息填写!");
                return false; 
            }
            if (!int.TryParse(tbxID.Text, out _))
            {
                MessageBox.Show("学号请填写数字!");
                return false;
            }
            foreach (RadioButton radioButton in gbxGender.Controls)
            {
                if (radioButton.Checked)
                {
                    return true;
                }
            }
            MessageBox.Show("请选择性别!");

            return false;
        }
        private void btnRegister_Click(object sender, EventArgs e)
        {
            if (!AreAllFieldsFilled())
            {
                clearInputs();
                return;
            }

            string ID =tbxID.Text;
            string Name = tbxName.Text;
            string gender = null;
            foreach (RadioButton g in gbxGender.Controls)
            {
                if (g.Checked)
                {
                    gender = g.Text;
                }
            }
            DateTime birthDate = dTimePkBirth.Value;
            DateTime birthDateOnly = birthDate.Date; // 获取日期部分,忽略时间

            StudentsDataBaseConnector studentsDataBaseConnector = StudentsDataBaseConnector.GetInstance();
            OleDbConnection connection = studentsDataBaseConnector.GetStudentDataBaseConnection();

            // 检查学号是否已存在
            string checkIDSql = "SELECT COUNT(*) FROM StudentsLogin WHERE 学号 = @ID";
            OleDbCommand checkIDCommand = new OleDbCommand(checkIDSql, connection);
            checkIDCommand.Parameters.AddWithValue("@ID", int.Parse(ID));
            int count = (int)checkIDCommand.ExecuteScalar();

            if (count > 0)
            {
                MessageBox.Show("学号已存在,请重新输入!");
                clearInputs();
                return;
            }
          

            string register_data_info = $"将注册以下信息:\n学号: {ID}\n姓名: {Name}\n性别: {gender}\n出生日期: {birthDate.ToShortDateString()}";
            MessageBox.Show(register_data_info);
            clearInputs();

       

            try
            {
                // 构造SQL INSERT语句
                string sql = "INSERT INTO StudentsLogin (学号, 姓名, 性别,出生日期) VALUES (@ID, @Name, @Gender,@BirthDate)";

                // 创建OleDbCommand对象
                OleDbCommand command = new OleDbCommand(sql, connection);

                // 添加参数并赋值
                command.Parameters.AddWithValue("@ID", int.Parse(ID));
                command.Parameters.AddWithValue("@Name", Name);
                command.Parameters.AddWithValue("@Gender", gender);
                command.Parameters.AddWithValue("@BirthDate", birthDateOnly);
         

                // 执行SQL语句
                command.ExecuteNonQuery();

                MessageBox.Show("注册成功!");
            }
            catch (Exception ex)
            {
                // 处理异常
                MessageBox.Show($"注册失败: {ex.Message}");
            }
            finally
            {
                // 关闭数据库连接
                if (connection.State == ConnectionState.Open)
                {
                    connection.Close();
                }
            }
        }

        private void btnGoBack2Main_Click(object sender, EventArgs e)
        {
            //如果用户有填写部分信息,提示用户是否返回
            if (!string.IsNullOrEmpty(tbxID.Text) ||
      !string.IsNullOrEmpty(tbxName.Text) ||
      gbxGender.Controls.OfType<RadioButton>().Any(rb => rb.Checked))
            {
                // 弹出确认对话框
                DialogResult dialogResult = MessageBox.Show("您有未保存的信息,确定要返回吗?", "确认", MessageBoxButtons.YesNo);
                if (dialogResult == DialogResult.Yes)
                {
                    // 用户确认返回
                    clearInputs();
                   
                    this.Close();
                }
            }else
            {
                this.Close();
            }

        }
    }
}


6 登录页面

  • 登录就是简单的数据查找,这里飞快过一下请添加图片描述
 StudentsDataBaseConnector studentsDataBaseConnector = StudentsDataBaseConnector.GetInstance();
 OleDbConnection connection = studentsDataBaseConnector.GetStudentDataBaseConnection();

 try
 {
     // 创建SQL查询命令
     string sql = "SELECT COUNT(*) FROM Login WHERE 学号 =@ID AND 姓名 =@Name";
     OleDbCommand command = new OleDbCommand(sql, connection);

     // 添加参数并赋值
     command.Parameters.AddWithValue("@ID", int.Parse(ID));
     command.Parameters.AddWithValue("@Name", Name);


     int count = (int)command.ExecuteScalar();

   
     if (count > 0)
     {
         MessageBox.Show("登录成功!");
   
     }
     else
     {
         MessageBox.Show("学号不存在或姓名错误!");
        
     }
 }
 catch (Exception ex)
 {
 
     MessageBox.Show("登录过程中发生错误: " + ex.Message);
 }
 finally
 {

     if (connection != null)
     {
         connection.Close();
     }
 }
6-2 登录页面完整代码
  • LoginForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StudentDatasetsExplorer
{
    public partial class LoginForm : Form
    {
        public LoginForm()
        {
            InitializeComponent();
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(tbxID.Text) || string.IsNullOrEmpty(tbxName.Text))
            {
                MessageBox.Show("请确认信息填写!");
                tbxName.Clear();
                tbxID.Clear();
                return;
            }
            if (!int.TryParse(tbxID.Text, out _))
            {
                MessageBox.Show("学号请填写数字!");
                tbxName.Clear();
                tbxID.Clear();
                return;
            }
            string Name=tbxName.Text;
            string ID=tbxID.Text;
            Console.WriteLine("ID:{0}, Name:{1}", ID, Name);


            StudentsDataBaseConnector studentsDataBaseConnector = StudentsDataBaseConnector.GetInstance();
            OleDbConnection connection = studentsDataBaseConnector.GetStudentDataBaseConnection();

            try
            {
                // 创建SQL查询命令
                string sql = "SELECT COUNT(*) FROM Login WHERE 学号 =@ID AND 姓名 =@Name";
                OleDbCommand command = new OleDbCommand(sql, connection);

                // 添加参数并赋值
                command.Parameters.AddWithValue("@ID", int.Parse(ID));
                command.Parameters.AddWithValue("@Name", Name);


                int count = (int)command.ExecuteScalar();

              
                if (count > 0)
                {
                    MessageBox.Show("登录成功!");
              
                }
                else
                {
                    MessageBox.Show("学号不存在或姓名错误!");
                   
                }
            }
            catch (Exception ex)
            {
            
                MessageBox.Show("登录过程中发生错误: " + ex.Message);
            }
            finally
            {
           
                if (connection != null)
                {
                    connection.Close();
                }
            }

        }

        private void btnGoBack2Main_Click(object sender, EventArgs e)
        {
            DialogResult dialogResult = MessageBox.Show("您确定要退出登录吗?", "确认", MessageBoxButtons.YesNo);
            if (dialogResult == DialogResult.Yes)
            {
                tbxName.Clear();
                tbxID.Clear();
                this.Close();
            }
        }
    }
}


小结

  • 本节讲述了如何通过VS2022连接Access并通过SQL实现登录和注册对数据库的查找和增加
  • 下一期我们讲讲删除和修改的逻辑实现
  • 感谢大家对本教程的支持,如有错误,欢迎指出!
  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值