当前位置: 首页 > news >正文

C# Winform 三层架构

一、介绍

三层架构是 C# 桌面开发中比较常用的框架,是由 表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构组成,目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。

从三层架构可以看到,很类似于 Web 前端开发的 MVC 框架(视图View,模型Model,控制Contorller),但本质上也有不同的地方,比如都有视图(三层中叫 UI),Model ,三层中没有 Contorller,但 BLL 层和 Contorller 很类似。

一个项目如果用到了三层架构,这就必然要涉及到数据库,否则就没有必要用三层架构了,下面用一张图来表示,我百度看了很多的帖子,三层架构写的基本是有一些差异的,如果你看的资料和我写的不一样,那都是正常的。

另外,各种项目根据自己的需求来,并不是所有的PC软件都要求用三层架构,用程序集划分了代码的逻辑,才是三层架构真正的意义所在。现在网上已经有很多三层架构自动生成生成软件,可以根据 sqlserver 数据库一键生成,但基本都是2016年之前的软件了,后面也没再更新了,有需要的话可以去试试。

二、搭建三层架构

新建一个基于.net6 的 winform 项目,就以登陆功能作为演示,界面如下

1.Model

添加一个 .net6 类库,取名 Model(存储数据库字段),在里面添加一个类 UserInfo

代码:

namespace Model
{
    public class UserInfo
    {
        public string? UserName { get; set; }
        public string? Password { get; set; }
    }
}

一般你数据库用户表的所有字段都要写出来,主要是方便后面将查询的数据以类对象的方式返回回来。

2.DAL

添加一个 .net6 类库,取名 DAL(数据访问层),在里面添加一个类 SqlServerHelper,这里看你用的什么数据库,如果是 mysql 就用 mysql 的查询方式,c# 查询 mysql 和 sqlserver 数据库我都有写相关的教程,有需要的可以去看看

C# 连接 SqlServer 数据库_熊思宇的博客-CSDN博客_c连接sqlserver数据库

C# 连接 MySQL 数据库_熊思宇的博客-CSDN博客_c# mysql

SqlServerHelper.cs

using System.Data;
using System.Data.SqlClient;
 
namespace SqlServer
{
    internal class SqlServerHelper
    {
        /// <summary>
        /// 连接字符串
        /// </summary>
        private string strconn = string.Empty;
 
        public SqlServerHelper(string conn)
        {
            //读取配置文件
            //strconn = ConfigurationManager.AppSettings["Conn"].ToString();
            //strconn = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
            strconn = conn;
        }
 
        /// <summary>
        /// 执行增删改SQL语句
        /// </summary>
        /// <param name="cmdText">SQL语句</param>
        /// <returns></returns>
        public int ExecuteNonQuery(string cmdText)
        {
            using (SqlConnection conn = new SqlConnection(strconn))
            {
                conn.Open();
                return ExecuteNonQuery(conn, cmdText);
            }
        }
 
        /// <summary>
        /// 执行增删改SQL语句
        /// </summary>
        /// <param name="conn">SqlConnection</param>
        /// <param name="cmdText">SQL语句<</param>
        /// <returns></returns>
        public int ExecuteNonQuery(SqlConnection conn, string cmdText)
        {
            int res;
            using (SqlCommand cmd = new SqlCommand(cmdText, conn))
            {
                cmd.CommandType = CommandType.Text;
                res = cmd.ExecuteNonQuery();
                if (conn.State == ConnectionState.Open)
                {
                    conn.Close();
                    conn.Dispose();
                }
            }
            return res;
        }
 
        /// <summary>
        /// 执行查询SQL语句
        /// </summary>
        /// <param name="cmdText">SQL语句</param>
        /// <returns></returns>
        public DataTable ExecuteDataTable(string cmdText)
        {
            using (SqlConnection conn = new SqlConnection(strconn))
            {
                conn.Open();
                return ExecuteDataTable(conn, cmdText);
            }
        }
 
        /// <summary>
        /// 执行查询SQL语句
        /// </summary>
        /// <param name="conn">SqlConnection</param>
        /// <param name="cmdText">SQL语句</param>
        /// <returns></returns>
        private DataTable ExecuteDataTable(SqlConnection conn, string cmdText)
        {
            DataTable dt = new DataTable();
            using (SqlCommand cmd = new SqlCommand(cmdText, conn))
            {
                cmd.CommandType = CommandType.Text;
                using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
                {
                    sda.Fill(dt);
                    if (conn.State == ConnectionState.Open)
                    {
                        conn.Close();
                        conn.Dispose();
                    }
                }
            }
            return dt;
        }
 
        /// <summary>
        /// 执行查询SQL语句
        /// </summary>
        /// <param name="cmdText">SQL语句</param>
        /// <returns></returns>
        public DataTable ExecuteQuery(string cmdText)
        {
            using (SqlConnection conn = new SqlConnection(strconn))
            {
                conn.Open();
                return ExecuteQuery(conn, cmdText);
            }
        }
 
        /// <summary>
        /// 执行查询SQL语句
        /// </summary>
        /// <param name="conn">SqlConnection</param>
        /// <param name="cmdText">SQL语句</param>
        /// <returns></returns>
        public DataTable ExecuteQuery(SqlConnection conn, string cmdText)
        {
            DataTable dt = new DataTable();
            using (SqlCommand cmd = new SqlCommand(cmdText, conn))
            {
                using (SqlDataReader sdr = cmd.ExecuteReader())
                {
                    dt.Load(sdr);
                    sdr.Close();
                    sdr.Dispose();
                    if (conn.State == ConnectionState.Open)
                    {
                        conn.Close();
                        conn.Dispose();
                    }
                }
            }
            return dt;
        }
 
    }
}

如果确少对应的插件,可以自己装一个

新建一个类 UserHandle,用来查询数据库并返回数据

using System.Data;

namespace DAL
{
    public class UserHandle
    {
        private const string Conn = "server=.;dataBase=Test;uid=sa;pwd=123456";
        private static SqlServerHelper SqlServerHelpers = new SqlServerHelper(Conn);

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public static DataTable UserLogin(string name ,string pwd)
        {
            // SQL 语句根据个人情况来写
            string sql = "SELECT * FROM **********";
            return SqlServerHelpers.ExecuteDataTable(sql);
        }

        /// <summary>
        /// 获取用户的所有数据
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static DataTable GetUserData(string name)
        {
            // SQL 语句根据个人情况来写
            string sql = "SELECT * FROM *************";
            return SqlServerHelpers.ExecuteDataTable(sql);
        }
    }
}

3.BLL

添加一个 .net6 类库,取名 BLL(业务逻辑层),由于后面的代码需要获取到数据库数据,所以要添加 DAL 和 Model 程序集 的引用

 添加一个类 LoginHandle

using DAL;
using Model;
using System.Data;

namespace BLL
{
    public class LoginHandle
    {

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <returns>是否能够登录</returns>
        public static bool UserLogin(string username, string password)
        {
            DataTable dataTable = UserHandle.UserLogin(username, password);
            if (dataTable == null || dataTable.Rows.Count == 0)
            {
                Console.WriteLine("查询的数据为空");
                return false;
            }

            string? user = dataTable.Rows[0][0].ToString();
            string? pwd = dataTable.Rows[0][1].ToString();
            if (username.Equals(user) && password.Equals(pwd))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 获取用户的所有数据
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        public static UserInfo? GetUserData(string username)
        {
            DataTable dataTable = UserHandle.GetUserData(username);
            if (dataTable == null || dataTable.Rows.Count == 0)
            {
                Console.WriteLine("查询的数据为空");
                return null;
            }

            UserInfo userInfo = new UserInfo();
            userInfo .UserName = dataTable.Rows[0][0].ToString();
            userInfo .Password = dataTable.Rows[0][1].ToString();

            return userInfo;
        }
    }
}

4.UI

UI层就是创建项目时的 winform 项目,上面的工作完成后,配置大概就如下界面

接下来就添加项目引用了,将 BLL和 Model 层添加进来

给界面的登录按钮,添加点击事件

using BLL;
using Model;

namespace 三层架构Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Button_Login_Click(object sender, EventArgs e)
        {
            string username = TextBox_UserName.Text;
            string password = TextBox_Password.Text;

            if(string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                Console.WriteLine("输入框不能为空");
                return;
            }

            //第一种方式
            bool result = LoginHandle.UserLogin(username, password);
            if(result)
            {
                Console.WriteLine("登录成功!");
                //跳转界面
                //....
            }
            else
            {
                Console.WriteLine("登录失败");
            }


            //第二种方式
            UserInfo? userInfo = LoginHandle.GetUserData(username);
            if(userInfo != null)
            {
                if(userInfo.Password != password)
                {
                    Console.WriteLine("密码不正确");
                    return;
                }

                Console.WriteLine("登录成功!");
            }
        }
    }
}

 源码:点击下载

结束

如果这个帖子对你有所帮助,欢迎 关注 、点赞 、留言

end

相关文章:

  • Opencv项目实战:18 人体姿态检测
  • MySQL修改表结构原理
  • 还在手动发早安吗?教你用java实现每日给女友微信发送早安
  • 【圣诞节】飘雪圣诞树
  • Python圣诞树
  • 【C与数据结构】——寒假提高每日练习Day1
  • 拦截器与过滤器
  • Web前端105天-day63-HTML5_CORE
  • Golang后端开发学习之路
  • C++——STL之stack和queue详解
  • 结构体嵌套函数指针
  • 基于Xlinx的时序分析与约束(4)----主时钟约束
  • Arcgis使用教程(十三)ARCGIS地图制图之地图输出参数设置详解
  • QT中Qthread线程彻底销毁的实例与注意事项(防止线程资源内存泄露)
  • PCL点云处理之曲面法线估计(八十二)
  • ES6指北【2】—— 箭头函数
  • [nginx文档翻译系列] 控制nginx
  • 2019.2.20 c++ 知识梳理
  • Android组件 - 收藏集 - 掘金
  • CSS居中完全指南——构建CSS居中决策树
  • docker容器内的网络抓包
  • gf框架之分页模块(五) - 自定义分页
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Meteor的表单提交:Form
  • redis学习笔记(三):列表、集合、有序集合
  • SpiderData 2019年2月25日 DApp数据排行榜
  • vue:响应原理
  • vue脚手架vue-cli
  • 从输入URL到页面加载发生了什么
  • 高度不固定时垂直居中
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 学习ES6 变量的解构赋值
  • 从如何停掉 Promise 链说起
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • (11)MATLAB PCA+SVM 人脸识别
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (52)只出现一次的数字III
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (Java)【深基9.例1】选举学生会
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (十三)Maven插件解析运行机制
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)jdk与jre的区别
  • .describe() python_Python-Win32com-Excel
  • .net实现客户区延伸至至非客户区
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @GetMapping和@RequestMapping的区别
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @德人合科技——天锐绿盾 | 图纸加密软件有哪些功能呢?