在winform中使用三層架構學習總結
阿新 • • 發佈:2019-02-07
Winform 三層架構小例子
http://www.cnblogs.com/jacky73/archive/2009/09/01/1558083.html在web開發中常常用到工廠模式三層架構,現在也在Winform中應用這種架構方式,嘗試了很多,也模仿了經典例子PetShop,但是還是不行,也參考了網上的一些例子。現在把我這個例子的整個製作過程簡單的介紹一下。(由於本例子是介紹三層結構,所以只是簡單的應用,如果你覺得這種方式好,請自己實現其他模組)
結構:
-------PMIS--------主程式程式碼
表示層,負責應用程式的表現形式、使用者體驗等。
-------DALFactory-----抽象工廠
抽象工廠,用於建立各種資料物件的方法,這裡有配置檔案和反射的運用。
-------IDAL--------資料介面層(控制是選擇什麼型別的資料庫)
資料操作介面,資料訪問層實現其介面並重寫它(體現了面向介面的程式設計思想)。
-------BLL------
處理應用程式的業務邏輯,被表示層呼叫。
-------Model-------構造模型(對應資料庫欄位)
Model程式集,存放實體類,用於資料訪問層和邏輯層呼叫
-------SQLServerDAL----SQLServer資料訪問層
資料訪問層,實現具體的select、update、delete....操作,重寫IDAL介面。
-------DBUtility----公共資料訪問層
資料處理層,實現具體的ExecuteReader,ExecuteDataTable,ExecuteNonQuery等。
-------Utility----公共層
實現從配置檔案中讀取資料庫聯接字串。
1、資料庫結構
資料庫名PMIS
表Admin
[ID] [bigint] 編號
[Name] [varchar](10) 名稱
[PassWord] [varchar](100) 密碼
略......
建表語句
CREATE TABLE [dbo].[Admin](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [varchar](10) COLLATE Chinese_PRC_CI_AS NOT NULL,
[PassWord] [varchar](100) COLLATE Chinese_PRC_CI_AS NOT NULL,
[PurviewID] [int] NOT NULL,
[Remember] [int] NULL,
[AutoRun] [int] NULL,
[DepartmentsID] [bigint] NULL,
CONSTRAINT [PK_管理員_1] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
2、接著建立資料庫模型
Model
#region 內部成員欄位
private int _id;
private string _Name;
private string _Password;
略...
#endregion
#region 方法
public AdminInfo() { }
public AdminInfo(string userName, string password)
{
this._Name = userName;
this._Password = password;
}
#endregion
3、建立DALFactory-----抽象工廠
public static IDAL.IAdmin Create()
{
string path=System.Configuration.ConfigurationSettings.AppSettings["DAL"];
string className="SQLServerDAL.Admin";
IDAL.IAdmin acount=(IDAL.IAdmin)Assembly.Load(path).CreateInstance(className);
return acount;
}
4、建立IDAL--------資料介面層
public interface IAdmin
{
AdminInfo Login(string userName, string password);
int Insert(AdminInfo account);
int Update(AdminInfo account);
}
5、建立Utility----公共層
public static string ConnectionString()
{
return (ConfigurationSettings.AppSettings["ConnectionString"]);
}
6、建立DBUtility----公共資料訪問層和SQLServer資料訪問層
DBUtility中建立SQLHelper類
SQLServerDAL的Admin類需要繼承IAdmin
public class Admin:IAdmin
{}
Admin類主要實現使用者登陸功能
7、建立業務邏輯曾BLL
方法public static AdminInfo Login(string userName, string password){}
8、為PMIS主程式新增應用程式配置檔案app.config
新增<appSettings>
<add key="ConnectionString" value="server=.;uid=sa;pwd=;database=PMIS"></add>
<add key="DAL" value="SQLServerDAL"></add>
</appSettings>
在主程式的窗體中新增控制元件,為按鈕新增事件
if (BLL.Admin.Login(引數) == null)
{
//處理...
}
else
{
//處理...
}
========
C# 使用三層架構例項演示-winForm 窗體登入功能
什麼是三層架構?百度百科講的很詳細,大家可以去搜索。這篇文章並不是討論這個問題。而是通過一個例子幫助大家理解三層。理論上的東西講的比較少。希望可以幫助到像我這樣的小白學習。希望可以幫助到大家!
個人覺得這個例子還是很基礎的,但是也可以幫助大家理解三層的設計理念。完成了這個小例子之後,你可以輕鬆的建立擁有相同功能的asp頁面,而不需要更改太多的程式碼,因為程式碼處理的邏輯與資料操作已經實現了,只需更改網頁空間屬性及呼叫方法即可,同時幫助瞭解分層的便利性。至於三層的缺陷,大家可以在以後的開發中慢慢了解。
好了廢話不說了,下面我們就直接開始正文吧。
資料庫設計相當簡單,就一個數據庫然後又張存著使用者名稱和密碼的表。
資料庫設計:
資料庫名稱:threeLayer
表: users
列:1.username 賬號 2.password 密碼
資料庫建立表的指令碼如下:
[sql] view plain copy
CREATE TABLE [dbo].[users](
[id] [int] IDENTITY(1,1) NOT NULL,
[username] [varchar](50) NULL,
[password] [varchar](50) NULL,
CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[users] ON
INSERT [dbo].[users] ([id], [username], [password]) VALUES (1, N'admin', N'admin')
INSERT [dbo].[users] ([id], [username], [password]) VALUES (2, N'user1', N'user1')
INSERT [dbo].[users] ([id], [username], [password]) VALUES (3, N'user2', N'user2')
INSERT [dbo].[users] ([id], [username], [password]) VALUES (4, N'user3', N'user3')
SET IDENTITY_INSERT [dbo].[users] OFF
三層資料傳遞整體思路:
使用者輸入賬號密碼->點選登入->進入BLL層進行輸入與資料的邏輯處理->進入DAL層將BAL層的邏輯進行實現(使用者輸入的賬號的密碼與資料庫匹配),返回結果
其中資料的傳遞用model實體類屬性來傳遞
步驟:
新建一個windows 窗體應用程式專案並命名為threeLayerText,路徑自己選吧,可以選擇回收站
在自動新建的窗體專案中,雙擊Form1.cs,開啟窗體設計。
在窗體中新增兩個label,兩個TextBox分別命名為textBoxAccount、textBoxtextBoxPsw和一個button 命名
為 butLogin。這裡命名指的是控制元件name屬性
為窗體新增一個應用配置檔案:右鍵窗體專案檔案-新增-新建項-應用程式配置檔案
在配置檔案<configuration>節點中新增資料庫連線語句
根據資料庫配置Initial Catalog 為資料庫名稱,User ID 為登入資料庫賬戶,Password 為改賬號密碼
新增後app.config完整內容如下
[html] view plain copy
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="dbConnection" connectionString="Data Source=.;Initial Catalog=threeLayer;Persist Security Info=True;User ID=sa;Password=123"
providerName="SQLClient" />
</connectionStrings>
</configuration>
新增類庫:右鍵專案解決方案-新增-新建專案-類庫,命名,確定
分別新增DAL、BAL、Model三個類庫
在Model類庫中新增userInfo類,用於在各個層之間傳遞資料
在類庫中新建一個使用者類 userInfo:右鍵Model類庫-新增-類(或者選中model類庫,使用shift+alt+c快捷鍵)
在userInfo類中新增屬性
[csharp] view plain copy
private string _username;
private string _psw;
public string username
{
set { _username = value; }
get { return _username; }
}
public string psw
{
set { _psw = value; }
get { return _psw; }
}
Model類完整程式碼如下:
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Model
{
public class userInfo
{
private string _username;
private string _psw;
public string username
{
set { _username = value; }
get { return _username; }
}
public string psw
{
set { _psw = value; }
get { return _psw; }
}
}
}
在DAL層中新增資料連線、查詢操作類和方法
新增system.configuration引用,使類可以讀取配置檔案節點,讀取配置檔案中連線資料庫語句;右鍵引用-新增引用-選擇程式集-勾選-確定
新增 DBbase類(右鍵DAL專案-新增-新建項-命名好-確定) 用於連線資料庫,新增System.Data 和 System.Data.SqlClient 名稱空間,別問我用來幹嗎,其實我也不知道用來幹嗎的。
建立一個基本的查詢方法用於查詢並返回記錄條數。DBbase類完整程式碼如下:
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace DAL
{
public class DBbase
{
//讀取配置檔案 連線資料庫語句
public static string strCon = System.Configuration.ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
//public static string strCon = "Data Source=.;Initial Catalog=threeLayer;Persist Security Info=True;User ID=sa;Password=123";
//例項化連線物件 con
SqlConnection con = new SqlConnection(strCon);
//檢測連線是否開啟
public void chkConnection()
{
if (this.con.State == ConnectionState.Closed)
{
this.con.Open();
}
}
//執行語句,返回該語句查詢的資料行的總數
public int returnRowCount(string strSQL)
{
chkConnection();
try
{
SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
DataSet ds = new DataSet();
da.Fill(ds);
return ds.Tables[0].Rows.Count;
}
catch
{
return 0;
}
}
}
}
新增 userAccess類(右鍵DAL專案-新增-新建項-命名好-確定) 用執行查詢語句查詢使用者輸入賬號密碼在資料庫中存在記錄條數
userAccess類完整程式碼如下:
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DAL
{
public class userAccess
{
//例項化DBbase 物件
DBbase db = new DBbase();
//使用者登入的方法
public int userLogin(string name, string psw)
{
string strsql = "select * from users where username = '" + name + "' and password = '" + psw + "'";
return db.returnRowCount(strsql);
}
}
}
在BLL層中新增使用者輸入資料與資料庫匹配的邏輯程式碼
新增Model、DAL類庫引用:右鍵BLL類庫中引用資料夾,右鍵-新增引用-選擇解決方案-專案-選中Model、DAL-確定
例項化DAL.userAccess 類,並新建一個方法呼叫DAL.userAccess方法,引數為Model實體類中的useInfo類,完整程式碼如下:
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BLL
{
public class userAccess
{
DAL.userAccess d_userAccess = new DAL.userAccess();
public int userLogin(Model.userInfo m_userInfo)
{
return d_userAccess.userLogin(m_userInfo.username, m_userInfo.psw);
}
}
}
回到窗體設計中,新增使用者輸入處理與呼叫BLL層方法
新增Model、DAL類庫引用:右鍵threeLayerText專案中引用資料夾,右鍵-新增引用-選擇解決方案-專案-選中Model、BLL-確定
開啟窗體後臺程式碼,例項化Model.userInfo 、BLL.userAccess。程式碼如下
[csharp] view plain copy
//例項化model層中 userInfo類用於傳遞資料
Model.userInfo m_userInfo = new Model.userInfo();
//例項化BLL層中 userAccess方法銜接使用者輸入與資料庫匹配
BLL.userAccess b_userAccess = new BLL.userAccess();
雙擊登入按鈕,新增點選事件。程式碼如下
[csharp] view plain copy
//將使用者輸入的賬號密碼 賦值給userInfo類 username、psw屬性
m_userInfo.username = textBoxAccount.Text.Trim().ToString();
m_userInfo.psw = textBoxPsw.Text.Trim().ToString();
//如果BLL層中 useLogin呼叫返回記錄條數 大於1 則賬號密碼正確
if (b_userAccess.userLogin(m_userInfo) > 0)
{
MessageBox.Show("登入成功");
}
else
{
MessageBox.Show("登入失敗");
}
完整Form1.cs 程式碼如下
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace threeLayerText
{
public partial class Form1 : Form
{
//例項化model層中 userInfo類用於傳遞資料
Model.userInfo m_userInfo = new Model.userInfo();
//例項化BLL層中 userAccess方法銜接使用者輸入與資料庫匹配
BLL.userAccess b_userAccess = new BLL.userAccess();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
//登入按鈕 事件
private void butLogin_Click(object sender, EventArgs e)
{
//將使用者輸入的賬號密碼 賦值給userInfo類 username、psw屬性
m_userInfo.username = textBoxAccount.Text.Trim().ToString();
m_userInfo.psw = textBoxPsw.Text.Trim().ToString();
//如果BLL層中 useLogin呼叫返回記錄條數 大於1 則賬號密碼正確
if (b_userAccess.userLogin(m_userInfo) > 0)
{
MessageBox.Show("登入成功");
}
else
{
MessageBox.Show("登入失敗");
}
}
}
}
儲存,可以除錯了。
關於Model實體層的描述:
Model又叫實體類,這個東西,大家可能覺得不好分層。我是這樣理解的:UI<-->Model<-->BLL<-->Model<-->DAL,如此則認為Model在各層之間起到了一個數據傳輸的橋樑作用。不過在這裡,我們不是把事情想簡單,而是想複雜了。
摘自:http://www.cnblogs.com/sdjxcolin/archive/2008/12/12/1353780.html 這篇文章講解了這個問題
========
C#中三層架構UI、BLL、DAL、Model實際操作
三層架構分為:表現層(UI)、業務邏輯層(BLL)、資料訪問層(DAL)再加上實體類庫(Model)
1、實體類庫(Model),主要存放資料庫中的表字段。
操作:
(1)先建立實體類庫Model,開啟專案,在解決方案中右鍵--》新增--》新建專案--》選中類庫--》改名Model--》確定
(2)選中Model類庫--》Shift+ALT+C--》建立實體類。UserInfo類
[csharp] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
namespace Model
{
public class UserInfo
{
public string UserName { get; set; }
public string Password { get; set; }
}
}
2、資料訪問層(DAL),主要是存放對資料類的訪問,即對資料庫的新增、刪除、修改、更新等基本操作
操作:
(1)先建立資料訪問層類庫DAL,開啟專案,在解決方案中右鍵--》新增--》新建專案--》選中類庫--》改名DAL--》確定
(2)在DAL中新增對Model的引用,選中DAL--》Alt+P+R--》解決方案--》專案--》選中MOdel--》確定
(3)在DAL中新增對system.configuration的引用,選中DAL--》Alt+P+R--》程式集--》框架--》選中System.configuration--》確定
(4)建立資料訪問類,選中DAL--》Shift+ALT+C--》建立資料訪問類。UserDB類
[csharp] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
using System.Configuration;
using Model;
using System.Data;
using System.Data.SqlClient;
namespace DAL
{
class UserDB
{
private string connString = ConfigurationManager.ConnectionStrings["connString"].ToString();
public int AddUser(UserInfo userInfo)
{
//對資料庫進新增一個使用者操作
string commandText = "insert into UserInfo (userName,Password)values(@userName,@Password)";
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter ("@userName",userInfo.UserName ),
new SqlParameter ("@Password",userInfo.Password )
};
return SqlHelper.ExecuteNonQuery(connString, CommandType.Text, commandText, paras);
}
}
[csharp] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
//新增其他對資料庫操作
}
3、業務邏輯層(BLL)對傳送資料進行邏輯判斷分折,並進行傳送正確的值。
(1)先建立業務邏輯層類庫BLL,開啟專案,在解決方案中右鍵--》新增--》新建專案--》選中類庫--》改名BLL--》確定
(2)在BLL中新增對Model、DAL的引用,選中BLL--》Alt+P+R--》解決方案--》專案--》選中MOdel、DAL--》確定
(3)建立業務邏輯類,選中BLL--》Shift+ALT+C--》建立業務邏輯類。LoginManager類
[csharp] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
using DAL;
using Model;
namespace BLL
{
public class LoginManager
{
private UserDB userDB = new UserDB();
public bool Add(UserInfo userInfo, out string messageStr)
{
messageStr = "";//返回介面層新增使用者返回資訊
bool isSuccess = false;
if (userInfo.UserName.Trim().Length != 0)//判斷從傳遞來的username是否為空
{
if (userDB.IsEquals(userInfo))//傳給DALl操作判斷資料庫中是否有重複值
{
userDB.AddUser(userInfo);//傳給DAL操作增加一個新使用者
isSuccess = true;
}
else
messageStr = "有相同的值";
}
else
{
messageStr = "不能為空";
}
return isSuccess;//返回介面層是否新增成功
}
}
}
5、表現層(UI)即使用者介面層
(1)在UI中新增對Model、BLL的引用,選中UI--》Alt+P+R--》解決方案--》專案--》選中MOdel、BLL--》確定
(2)編寫程式碼傳遞資料給BLL層。
[csharp] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
UserInfo userInfo;
LoginManager lm = new LoginManager();
private void btnAdd_Click(object sender, EventArgs e)
{
userInfo = new UserInfo()
{
UserName = txtUserName.Text.Trim(),
Password = txtPassword.Text.Trim()
};
string messageStr = "";
if (lm.Add(userInfo, out messageStr))
{
MessageBox.Show("新增成功");
}
else
{
MessageBox.Show(messageStr);
txtUserName.Focus();
}
}
}
========
用三層架構來做winform程式
三層架構是一種程式碼分層思想,簡單的說就是將一個專案分為介面展示、業務邏輯、資料訪問三層,各層之間保持一定的獨立性,降低程式碼之間的耦合性,這樣做的好處是顯而易見的:
1、各層之間的改動不會影響到其他層(比較大的變動除外,如果客戶要求業務流程、資料庫結構都變了,你還期望有什麼不會變呢)
2、基本不用寫SQL語句了,自動生成的程式碼是引數化查詢,可以防止SQL注入
3、程式碼條理清楚,便於理解
當然三層架構不是拯救一切的靈丹妙藥,比如:
1、比較小的專案何必糾結用什麼架構呢,在你琢磨架構的時候,用winform可能已經寫完了
2、速度會有所降低,相對於直接訪問資料庫,三層架構增加了中間層,速度降低是肯定的
說到三層架構,可能第一時間想到的就是mvc,然而三層架構並不是web的專利,歸根結底,三層架構只是一種程式碼分層思想,winform當然也可以用,只不過介面展示這塊,mvc是網頁的形式,winform是windows窗體,其他兩層思路是一樣的。
下面就以一個非常簡單常見的商鋪展示程式來實際講解winform中如何實現三層架構。
一、前期準備
1、動軟程式碼生成器,國產神器,你值得擁有,全自動生成資料訪問層程式碼,百度就能找到,最後一版是2.78,作者沒有繼續更新了。已經免費開源,喜歡研究原始碼的可以繼續擴充套件。
李天平的部落格
http://blog.csdn.net/litp
http://www.cnblogs.com/ltp/category/44293.html
2、SQLiteStudio,選擇SQLite資料庫是因為輕巧、無需安裝,對於這個示例程式足夠用了 ,SQLiteStudio是免費好用的SQLite資料庫圖形化管理工具,百度可得綠色版。
二、開發過程
1、下載動軟程式碼生成器,安裝完成之後執行,連線到附件示例程式的SQLite資料庫,開啟連線,右鍵點選資料庫,選擇“新建.net專案”,選擇“簡單三層結構”,下一步,選擇“Shops”、“Users”兩個表,點選“開始生成”。
2、來到生成目錄,開啟原始碼,可以看到5個專案,下面分別說說他們的作用
BLL--業務邏輯層,所有的業務邏輯全部寫在這裡,動軟已經為每個表自動生成了一個業務類,類名就是表名,BasicMethod區段是自動生成的一些基礎方法,比如增刪改查、分頁查詢這些,ExtensionMethod區段是空的,我們自己寫的業務程式碼寫在這個區段。
DAL--資料訪問層,所有的資料庫訪問的基礎方法寫在這裡,動軟已經為每個表自動生成了一個數據訪問類,類名就是表名,BasicMethod區段是自動生成的一些基礎方法,比如增刪改查、分頁查詢這些,ExtensionMethod區段是空的,如果我們覺得這些基礎的資料庫操作方法不夠用,可以在這個區段新增自己的資料庫操作方法,但是隻有資料庫的操作方法應該寫在DAL類庫。
DBUtility--資料庫訪問的基礎類庫,封裝了MySQL,Sql,OLE,SqlLite,Oracle等資料庫訪問的方法,與ADO.NET相關的connection,DataAdapter,Command等全部在這裡,DAL是在DBUtility基礎上的進一步封裝的,這個類庫基本不需要修改。
Model--資料庫表結構的對映,每一個類名代表資料庫中的一個相同名字的表,類的每一個欄位、屬性表示表中對應的欄位,資料庫的一條記錄就對應類的一個物件,這個類庫基本不需要修改。
Web-- 一些基礎的網頁,因為我們是做winform的,所以這個不需要了,但是先別急著刪,等下我們還要來拷連線字串。
最後在解決方案資料夾下有一個Lib資料夾,是一些動態連結庫,看看上述每個專案缺什麼就引用什麼。
3、新建一個winform專案,在專案的屬性裡將目標框架設定為".net framework 4"(不是".net framework 4 profile"),這樣就有一個app.config檔案了,開啟app.config,開啟Web專案根目錄下的Web.config檔案,將appSettings整個一節拷貝到app.config檔案configuration節點內,將連線字串修改為SqlLite的格式,刪除Web專案。
補充一點,我們的程式是怎麼得到連線字串的呢?在DBUtility類庫裡,有一個PubConstant類,裡面有一個ConnectionString屬性,通過ConfigurationManager.AppSettings["ConnectionString"]讀取了app.config檔案裡儲存的連線字串。
接下來就是開始做介面,寫程式碼了,winform相信大家都很熟悉了,具體過程我就不多說了,直接上原始碼。
示例程式原始碼:
http://pan.baidu.com/s/1jIRZkfO
總結:
1、動軟自帶的SQLite動態連結庫比較老,用他原來的執行不起來,我換成了新版的,在Lib資料夾下的SQLite.Interop.dll和System.Data.SQLite.DLL,System.Data.SQLite.DLL需要在專案中引用,SQLite.Interop.dll要手動拷貝到生成目錄
2、如果程式碼寫完後資料庫結構發生了變化(比如增加了一個欄位),我能想到的辦法就是重新用動軟生成一次,將BLL,DAL,DBUtility,Model替換掉,所以最好這幾個專案中不要寫自己的程式碼了,要擴充套件的話重新建專案吧。為什麼不推薦手動改呢,因為即便是增加一個欄位,也可能涉及到幾個類的修改,改動大就更不用說了,手動改程式碼的話很有可能漏掉,能用最簡單的辦法搞定的事就用最簡單的辦法。
========