C#实现登录界面,三层架构项目分层,连接数据库验证账号密码正确性,泛型反射遍历获取的数据并转换成实体类型

首先是项目分层,三层架构分别为:

1、表现层(UI):通俗讲就是展现给用户的界面,即用户在使用一个系统的时候他的所见所得。

2、业务逻辑层(BLL):针对具体问题的操作,也可以说是对数据层的操作,对数据业务逻辑处理。

3、数据访问层(DAL):该层所做事务直接操作数据库,针对数据的增添、删除、修改、更新、查找等。

3个层次中,系统主要功能和业务逻辑都在业务逻辑层进行处理。

第一个窗体类是表示层,右键引用,勾选业务逻辑层和数据访问层

第二个类库是充血模型也是业务逻辑层,右键引用,引用数据访问层

第三个类库是帮助类也是数据访问层

接下来是连接数据库所需要的配置,首先进入窗体配置类App.config创建连接字符串

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<connectionStrings>
		<add name="Constr" connectionString="Data Source=LAPTOP-24VJ6OS7;database=Commodity;uid=sa;pwd=123456"/>
	</connectionStrings>
	<startup>
		<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
	</startup>
</configuration>

来到数据库帮助类SqlHelper.cs;当业务逻辑层调用sqlhelper类时,需要传入查询语句,查询会返回结果,增删改会返回影响行数,这个数据库帮助类可以应用到后续开发的所有数据库连接项目中

泛型反射类也可以应用到后续开发的所有项目中

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Commodity_System.Utility
{
    public class SqlHelper
    {
        public static string Constr { get; set; }//数据库链接字符串

        /// <summary>
        /// 查询数据库
        /// 1个参数传入sql语句
        /// </summary>
        /// <param name="cmdText">sql语句</param>
        /// <returns>返回查询结果</returns>
        public static DataTable ExecuteTable(string cmdText)
        {
            //var:推断数据类型,随机应变
            using (var conn = new SqlConnection(Constr))//创建Sqlconnection对象并传入连接字符串ConStr
            {
                conn.Open();//打开数据库连接
                SqlCommand cmd = new SqlCommand(cmdText, conn); //创建SqlCommand对象,并传入要执行的SQL查询语句cmdText和连接对象conn(管家)
                SqlDataAdapter sda = new SqlDataAdapter(cmd);//创建SqlDataAdapter对象,并传入SqlCommand对象(推车)
                DataSet ds = new DataSet();//创建DataSet对象,用于存储查询结果集(货车)
                sda.Fill(ds);//将查询结果填充到DataSet中(推车的东西填充到货车)
                return ds.Tables[0];//返回DataSet中的第一个表格(Tables[0]),即查询结果作为DataTable对象返回
            }
        }
        /// <summary>
        /// 增删改
        /// </summary>
        /// <param name="cmdText">sql语句</param>
        /// <returns>返回受影响的行数</returns>
        /// <exception cref="Exception">数据库操作失败</exception>
        public static int ExecuteNonQuery(string cmdText, params SqlParameter[] sqlParameter)//操作数据库并返回受影响的行数
        {
            using (SqlConnection conn = new SqlConnection(Constr))//创建SqlConnection对象并传入连接字符串ConStr
            {
                conn.Open();//打开数据库连接
                SqlCommand cmd = new SqlCommand(cmdText, conn);//创建SqlCommand对象,并传入要执行的SQL查询语句cmdText和连接对象conn
                cmd.Parameters.AddRange(sqlParameter);
                int rows = cmd.ExecuteNonQuery();//执行SQL命令并返回受影响的行数
                if (rows == 0)
                {
                    throw new Exception("数据库操作失败");
                }
                return rows;//返回受影响的行数
            }
        }
    }
}

泛型反射类ToModel:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Commodity_System.Utility
{
    public static class ToModel
    {
        public static ToModel DataRowToModel<ToModel>(this DataRow dr) //ToModel被定义为了泛型
        {
            Type type = typeof(ToModel);
            ToModel md = (ToModel)Activator.CreateInstance(type);
            foreach (var prop in type.GetProperties())
            {
                if (dr[prop.Name] != DBNull.Value)//如果有null传入,就不做类型转换,防止报错
                {
                    prop.SetValue(md, dr[prop.Name]);
                }
            }
            return md;
        }
    }
}

接下来在业务逻辑层中的CAdmin.cs(业务逻辑层类的命名和数据库中的表单名字一致,文章最后附上数据库的表单命名)调用数据库帮助类,完成查询数据

using Commodity_System.Utility;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Commodity_System.Models
{
    public class CAdmin
    {
        /// <summary>
        /// 唯一识别Id
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 用户账号
        /// </summary>
        public string UserId { get; set; }
        /// <summary>
        /// 姓名
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 用户密码
        /// </summary>
        public string password { get; set; }
        /// <summary>
        /// 性别
        /// </summary>
        public string sex { get; set; }
        /// <summary>
        /// 部门
        /// </summary>
        public string dept { get; set; }
        /// <summary>
        /// 授权码
        /// </summary>
        public string authorizationCode { get; set; }

        /// <summary>
        /// 获取CAdmin表所有的数据
        /// </summary>
        /// <returns>CAdmin表所有的数据</returns>
        public static List<CAdmin> ListAll()
        {
            DataTable dt = SqlHelper.ExecuteTable("SELECT" +
                "* from CAdmin");//调用帮助类传sql语句并用DataTable接收数据
            List<CAdmin> cAdmins = new List<CAdmin>();//存入泛型列表
            foreach (DataRow dr in dt.Rows)//这里用到了泛型反射
            {
                cAdmins.Add(dr.DataRowToModel<CAdmin>());
            }
            return cAdmins;//返回实体集
        }

查询到的数据需要返回给表示层,在表示层中的Login.cs窗体中调用业务逻辑层的方法验证账号密码正确性,当点击登录按钮时触发的事件,前面总结过账号密码的隐藏,大体框架在上篇文章

public static CAdmin admin;//定义业务逻辑层窗体类,方便调用里面设置好的参数

private void btnLogin_Click(object sender, EventArgs e)
{
    string userId = txtUserId.Text.Trim();
    string psw = txtPsw.Text.Trim();

    if (userId == "" || psw == "")
    {
        MessageBox.Show("用户名或密码不可为空", "提示");
    }
    else
    {
        int i = CAdmin.ListAll().FindIndex(t => t.UserId == userId && t.password == psw);//查询账号和相对应密码,获取其索引值(id)
        if(i > -1)
        {
            admin = CAdmin.ListAll()[i];
            DateTime date = DateTime.Now;
            string day = date.ToShortDateString();
            MessageBox.Show($"你好,{admin.name}\n今天是{day}","欢迎使用");
            this.Owner.Visible = true;//owen表示作为此窗体的所有者的窗体,即父窗体
            this.Owner.WindowState = FormWindowState.Normal;
            //解除下面关联的事件
            this.FormClosed -= new System.Windows.Forms.FormClosedEventHandler(this.Login_FormClosed);
            Close();
        }
        else
        {
            MessageBox.Show("登陆失败,账号或密码错误", "提示");
        }
    }
}

private void Login_FormClosed(object sender, FormClosedEventArgs e)
{
    Application.Exit();//退出程序
}

由于应用程序的主入口点设置的是Home.cs,只是隐藏起来了,先显示登录窗口,登录后显示主页

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Commodity_System
{
    public partial class Home : Form
    {
        public Home()
        {
            InitializeComponent();
        }

        private void Home_Shown(object sender, EventArgs e)
        {
            this.Visible = false;//每当窗体第一次显示时先隐藏
            new Login().Show(this);//显示登录窗体
        }

        private void Home_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (Visible)//只有当主页是可见状态时,才弹窗
            {
                if (MessageBox.Show("确定要关闭吗", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

登录后想在主页或其他窗体中调用登录时用的Id,UserId或姓名可以直接用以下方法直接拿,因为已经存入了Login的业务逻辑层窗体类admin中,这里只做提示

Id= Login.admin.Id
UserId= Login.admin.UserId
Name = Login.admin.name

数据库关系表:

 最终效果:

登录功能(数据库连接)

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值