課設(shè):數(shù)據(jù)庫設(shè)計到三種角色全流程解析)
簡介這份餐飲外賣銷售系統(tǒng)數(shù)據(jù)庫設(shè)計壓縮包基于C#與SQL Server 2019開發(fā)覆蓋商家、客戶、騎手三類角色界面及注冊登錄模塊面向高校數(shù)據(jù)庫課程設(shè)計參考適合需要完成同類業(yè)務(wù)系統(tǒng)設(shè)計的中高級學(xué)生。壓縮包共46個文件整體僅886KB其中13個C#源文件對應(yīng)各業(yè)務(wù)窗體與邏輯5組resx/resources界面資源文件用于控件樣式另有配置文件、圖片素材、可執(zhí)行程序等解決方案與項目文件齊全目錄結(jié)構(gòu)清晰可使用Visual Studio直接打開運行。目前已有1592人學(xué)習(xí)下載被廣泛用于數(shù)據(jù)庫課程設(shè)計參考。資源采用扁平化商業(yè)級界面設(shè)計代碼注釋詳細包含顧客注冊、商家登錄、商家管理等完整流程清晰體現(xiàn)多角色權(quán)限設(shè)計與數(shù)據(jù)庫交互思路從界面布局到業(yè)務(wù)編碼均具有較高參考價值是兼顧美觀度與可讀性的數(shù)據(jù)庫課設(shè)高分示例。1. 這就是數(shù)據(jù)庫課設(shè)該有的樣子從登錄到三種角色一套代碼全打通做過數(shù)據(jù)庫課設(shè)的人都知道最折磨人的不是建幾張表、寫幾條 SQL而是把表里的數(shù)據(jù)真正用起來登錄怎么校驗、商家怎么上架商品、騎手怎么接單、訂單狀態(tài)怎么流轉(zhuǎn)。這個資源正好卡在這個痛點上它是一套基于 C# 和 SQL Server 2019 的外賣銷售系統(tǒng)包含商家、客戶、騎手三種用戶界面和獨立的注冊界面界面走扁平化設(shè)計視覺完成度接近商業(yè)軟件。文件包里是完整的 Visual Studio 解決方案配置好數(shù)據(jù)庫環(huán)境后可以直接打開運行。適合正在做數(shù)據(jù)庫課設(shè)的高校學(xué)生也適合想?yún)⒖?C# WinForms 連接 SQL Server 這套鏈路怎么落地的開發(fā)者。下面我按自己拆項目的習(xí)慣從數(shù)據(jù)庫設(shè)計、環(huán)境配置、代碼邏輯到踩坑記錄一層層給你拆開講。2. 外賣業(yè)務(wù)的數(shù)據(jù)模型三張主表怎么設(shè)計才不打架2.1 從界面反推表結(jié)構(gòu)客戶、商家、騎手是三條獨立業(yè)務(wù)線這個項目里有三個注冊入口客戶注冊、商家注冊登錄界面則是三者共用。這種設(shè)計在數(shù)據(jù)模型上的第一反應(yīng)就是——三種用戶不能塞進同一張表。很多課設(shè)喜歡搞一張“用戶表”加一個“角色字段”省事但后續(xù)寫業(yè)務(wù)邏輯的時候會非常痛苦客戶的收貨地址、商家的店鋪名、騎手的接單范圍這些字段塞在一起表會越來越臃腫查詢效率也差。我拆完這個項目后推薦的數(shù)據(jù)模型是三張主表分立的方案表名核心字段職責(zé)邊界客戶表客戶ID、登錄名、密碼、手機號、收貨地址只存客戶身份與收貨信息商家表商家ID、登錄名、密碼、店鋪名稱、營業(yè)狀態(tài)只存商家身份與店鋪信息騎手表騎手ID、登錄名、密碼、手機號、接單狀態(tài)只存騎手身份與配送信息三張表各自獨立登錄時按入口分別查不同的表。這種設(shè)計的最大好處是權(quán)限邊界清晰商家界面只能操作商品和訂單客戶界面只能下單和評價騎手界面只能接單和更新配送狀態(tài)不會出現(xiàn)“一個用戶表里角色字段寫錯導(dǎo)致權(quán)限串了”的尷尬。2.2 訂單表與狀態(tài)流轉(zhuǎn)外賣系統(tǒng)里最考驗設(shè)計的關(guān)聯(lián)表外賣系統(tǒng)的核心業(yè)務(wù)是訂單而訂單表恰恰是課設(shè)里最容易設(shè)計翻車的地方。很多同學(xué)把訂單設(shè)計成一張“大而全”的表把客戶名、商家名、騎手名、商品名全都冗余進去看起來查詢方便實際上數(shù)據(jù)一致性極差。這個項目走的是標準的三范式思路訂單表只存外鍵關(guān)聯(lián)查詢時再 JOIN 取名字。常見的核心表設(shè)計是這樣的表名關(guān)鍵字段說明訂單表訂單ID、客戶ID、商家ID、騎手ID、訂單狀態(tài)、下單時間外鍵關(guān)聯(lián)三張用戶表訂單明細表明細ID、訂單ID、商品ID、商品數(shù)量、單價拆分多商品訂單商品表商品ID、商家ID、商品名稱、價格、庫存歸屬商家配送表配送ID、訂單ID、騎手ID、配送狀態(tài)、送達時間與騎手強關(guān)聯(lián)訂單狀態(tài)建議用 int 存儲而不是中文0 表示已提交、1 表示商家已接單、2 表示騎手配送中、3 表示已完成、4 表示已取消。用數(shù)字存儲的好處是狀態(tài)流轉(zhuǎn)的代碼判斷寫起來干凈也不會因為中文字符集問題在查詢時出幺蛾子。2.3 建庫的常見做法腳本化建庫比手工點界面靠譜拿到這個資源后你第一件事不是急著打開 Visual Studio而是先把數(shù)據(jù)庫建出來。常見做法是打開 SQL Server Management StudioSSMS新建一個數(shù)據(jù)庫外賣銷售系統(tǒng)然后按上面的表結(jié)構(gòu)逐一建表。但我更推薦把建庫腳本存成 .sql 文件這樣做的好處是答辯時老師問“你的數(shù)據(jù)庫怎么設(shè)計的”你直接展示腳本比在 SSMS 里現(xiàn)場點鼠標建表有說服力得多。建表腳本的核心結(jié)構(gòu)大致是這樣CREATE TABLE 客戶表 ( 客戶ID INT IDENTITY(1,1) PRIMARY KEY, 登錄名 NVARCHAR(50) UNIQUE NOT NULL, 密碼 NVARCHAR(100) NOT NULL, 手機號 NVARCHAR(20), 收貨地址 NVARCHAR(200) ); CREATE TABLE 商家表 ( 商家ID INT IDENTITY(1,1) PRIMARY KEY, 登錄名 NVARCHAR(50) UNIQUE NOT NULL, 密碼 NVARCHAR(100) NOT NULL, 店鋪名稱 NVARCHAR(100) NOT NULL, 營業(yè)狀態(tài) INT DEFAULT 1 );這段腳本里有幾個細節(jié)值得注意。IDENTITY(1,1) 讓主鍵自增避免業(yè)務(wù)代碼里手動維護 ID 出現(xiàn)重復(fù)登錄名加 UNIQUE 約束是防止注冊時出現(xiàn)重復(fù)賬號的數(shù)據(jù)庫層兜底密碼字段用 NVARCHAR(100) 而不是 NVARCHAR(20)因為實際項目中一般會存哈希值而不是明文。商家表的營業(yè)狀態(tài)用 INT 默認 11 表示營業(yè)中0 表示休息這樣商家界面上切換營業(yè)狀態(tài)時代碼只需要 UPDATE 這個字段。訂單表關(guān)聯(lián)外鍵時一個常見的坑是刪除客戶時如果該客戶名下已有訂單外鍵約束會直接報錯阻止刪除。解決方法是設(shè)計時就在訂單表上設(shè)置 ON DELETE NO ACTION或者干脆在業(yè)務(wù)層規(guī)定——有歷史訂單的用戶不允許物理刪除只允許邏輯禁用。這個項目里沒有復(fù)雜的級聯(lián)刪除需求所以外鍵約束保持默認即可。3. 把項目跑起來的完整路徑從 .sln 到數(shù)據(jù)庫連接串3.1 先讀懂解決方案結(jié)構(gòu)sln 和 csproj 各管什么事解壓資源包后你會看到一個主項目文件夾 Meituan里面有 Meituan.sln 和 Meituan.csproj。約定俗成的分工是.sln 是解決方案文件記錄這個項目包含哪些子項目.csproj 是 C# 項目文件記錄編譯配置、引用、入口程序等信息。雙擊 .sln 用 Visual Studio 打開所有窗體文件會出現(xiàn)在解決方案資源管理器里。窗體文件的組織方式是Form 名稱 Designer.cs resx 三件套。比如 Login 界面就是 Login.cs業(yè)務(wù)邏輯、Login.Designer.cs界面布局、Login.resx界面資源。這種結(jié)構(gòu)初學(xué)者最容易懵以為三個文件是三個界面其實它們是一個窗體的三面Designer.cs 里是控件的屬性賦值邏輯resx 里存的是這個窗體用到的圖片、圖標等資源真正的代碼寫在 .cs 里。啟動項目是 Program.cs這是 WinForms 應(yīng)用的入口文件。它的核心邏輯只有三件事我拆出來給你看[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Login()); }這里的 Application.Run(new Login()) 決定了程序啟動后第一個彈出的窗口是登錄界面。如果你想改成啟動后直接進入商家主界面把 new Login() 換成 new Businesses() 就行。但注意這樣的改動只適合測試正式流程必須經(jīng)過登錄驗證否則任何人都能跳過登錄直接進入系統(tǒng)。3.2 App.config 里的連接字符串最容易翻車的地方這個項目連的是 SQL Server 2019連接字符串配置在 App.config 文件里。App.config 是 C# 程序的配置文件編譯后會自動復(fù)制到輸出目錄并改名為 Meituan.exe.config程序運行時從這里讀取配置。典型的連接字符串長這樣?xml version1.0 encodingutf-8 ? configuration startup supportedRuntime versionv4.0 sku.NETFramework,Versionv4.7.2 / /startup connectionStrings add nameMeituanDB connectionStringData Source.;Initial Catalog外賣銷售系統(tǒng);Integrated SecurityTrue / /connectionStrings /configurationData Source.; 里的點號代表本機默認的 SQL Server 實例。但這里有個坑如果你安裝 SQL Server 2019 時給實例起了名字比如 SQLEXPRESS 或自定義名稱這個點號就連不上。我一般會建議把 Data Source 寫成 計算機名\實例名 的格式比如 DESKTOP-ABC123\SQLEXPRESS這樣最穩(wěn)。判斷本機實例名的方法是打開 SSMS登錄窗口的服務(wù)器名稱下拉框里顯示的就是完整的實例名。Integrated SecurityTrue 表示用 Windows 身份認證登錄數(shù)據(jù)庫。如果你的課設(shè)要求用 SQL Server 身份認證改成 User IDsa;Password你的密碼 即可。用 SQL Server 認證時密碼里有特殊字符比如 、#的話需要對字符做轉(zhuǎn)義處理否則連接字符串解析會出錯。3.3 打開即運行的前提先建庫再連串實際操作時最常遇到的場景是雙擊 .sln代碼編譯沒問題一運行就報“在建立與服務(wù)器的連接時出錯”。原因幾乎都是數(shù)據(jù)庫沒建或者連接字符串不對。正確的啟動順序是先在 SSMS 里把數(shù)據(jù)庫建好確認連接字符串指向的數(shù)據(jù)庫名和實例名正確再按 F5 運行。如果編譯時提示缺少引用看看 csproj 里引用的程序集是不是在你的本機環(huán)境里缺失。比如有些封裝好的第三方庫資源包里沒有附帶就需要你自己通過 NuGet 還原。但從這個項目的文件列表看引用的都是 System、System.Data、System.Drawing 這類 .NET 自帶程序集正常情況下不需要額外裝包。4. 登錄、注冊與三種角色界面業(yè)務(wù)代碼的實現(xiàn)與邊界4.1 登錄校驗的推薦寫法參數(shù)化查詢是底線登錄邏輯是整個系統(tǒng)最基礎(chǔ)也最容易被攻擊的環(huán)節(jié)。這個項目里登錄窗體的職責(zé)是接收用戶名和密碼去對應(yīng)的表里查是否存在匹配的記錄。很多課設(shè)代碼里直接用字符串拼接 SQL比如 str username str這在單機課設(shè)里跑著沒事但答辯老師只要問一句“SQL 注入怎么防”你就得當場改代碼。這個項目的代碼注釋里標注了詳細的參數(shù)說明推薦的寫法是參數(shù)化查詢private void btnLogin_Click(object sender, EventArgs e) { string role cmbRole.SelectedItem.ToString(); // 下拉框選擇角色 string loginName txtUsername.Text.Trim(); string password txtPassword.Text.Trim(); if (string.IsNullOrEmpty(loginName) || string.IsNullOrEmpty(password)) { MessageBox.Show(用戶名和密碼不能為空); return; } string tableName role 商家 ? 商家表 : role 客戶 ? 客戶表 : 騎手表; string sql SELECT COUNT(*) FROM tableName WHERE 登錄名loginName AND 密碼password; using (SqlConnection conn new SqlConnection(connStr)) { using (SqlCommand cmd new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue(loginName, loginName); cmd.Parameters.AddWithValue(password, password); conn.Open(); int count (int)cmd.ExecuteScalar(); if (count 0) { MessageBox.Show(登錄成功); // 根據(jù)角色打開不同的主界面 } else { MessageBox.Show(用戶名或密碼錯誤); } } } }這段代碼有三個要點。tableName 是根據(jù)角色下拉框動態(tài)選擇的表名對表名的拼接是安全的因為這是代碼里寫死的條件賦值不是用戶輸入密碼和用戶名都用了參數(shù)化方式傳入 SqlCommand數(shù)據(jù)庫會把參數(shù)當字面量處理從機制上杜絕了注入ExecuteScalar 返回的是首行首列的值COUNT() 正好適合這種只需要判斷存在與否的場景。注意 SELECT COUNT() 比 SELECT * 更高效因為數(shù)據(jù)庫不需要回表取完整記錄只返回計數(shù)結(jié)果。4.2 客戶注冊與商家注冊差異在必填字段的校驗注冊界面分成了客戶注冊和商家注冊兩個窗體這是合理的設(shè)計??蛻舻淖孕畔⒅恍枰卿浢?、密碼、手機號、收貨地址而商家注冊還需要店鋪名稱。字段不同意味著校驗規(guī)則和插入的 SQL 語句也不同??蛻糇缘暮诵倪壿嬍侨讲橹貜?fù)、校驗格式、插入數(shù)據(jù)。private void btnRegister_Click(object sender, EventArgs e) { string loginName txtLoginName.Text.Trim(); string password txtPassword.Text.Trim(); string phone txtPhone.Text.Trim(); string address txtAddress.Text.Trim(); if (!Regex.IsMatch(phone, ^1[3-9]\d{9}$)) { MessageBox.Show(手機號格式不正確); return; } string checkSql SELECT COUNT(*) FROM 客戶表 WHERE 登錄名loginName; string insertSql INSERT INTO 客戶表(登錄名,密碼,手機號,收貨地址) VALUES(loginName,password,phone,address); using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); using (SqlCommand cmd new SqlCommand(checkSql, conn)) { cmd.Parameters.AddWithValue(loginName, loginName); int count (int)cmd.ExecuteScalar(); if (count 0) { MessageBox.Show(該用戶名已被注冊); return; } } using (SqlCommand cmd new SqlCommand(insertSql, conn)) { cmd.Parameters.AddWithValue(loginName, loginName); cmd.Parameters.AddWithValue(password, password); cmd.Parameters.AddWithValue(phone, phone); cmd.Parameters.AddWithValue(address, address); cmd.ExecuteNonQuery(); MessageBox.Show(注冊成功); } } }這個實現(xiàn)里有兩個細節(jié)值得關(guān)注。先查重復(fù)再插入不是原子操作理論上兩個客戶端同時注冊相同用戶名時會產(chǎn)生競態(tài)但對課設(shè)場景沒關(guān)系數(shù)據(jù)庫層面的 UNIQUE 約束兜底了正則表達式 ^1[3-9]\d{9}$ 校驗的是國內(nèi)手機號格式如果你要改成其他規(guī)則直接替換正則表達式即可。變量名用了駝峰命名法查重用的 cmd 在 ExecuteScalar 之后處于空閑狀態(tài)直接再賦值新的 SQL 語句也能復(fù)用但用 using 包兩層更清晰舊連接會及時釋放。4.3 三種角色主界面同源數(shù)據(jù)的不同業(yè)務(wù)視圖商家、客戶、騎手三個主界面對應(yīng)三個窗體Businesses.cs、Customers.cs、以及騎手相關(guān)窗體。三個界面操作的是同一套數(shù)據(jù)庫但業(yè)務(wù)權(quán)限各不相同。商家界面主要操作商品表和訂單表客戶界面主要操作商品表和訂單表但視角不同——客戶看到的是可下單的商品列表商家看到的是待處理的訂單列表騎手看到的則是待接單的配送任務(wù)。這種“一個數(shù)據(jù)庫、三種視圖”的設(shè)計在代碼層面通常體現(xiàn)為對 DataGridView 控件綁定不同的數(shù)據(jù)源。商家界面加載商品列表的典型寫法是private void LoadProducts() { string sql SELECT 商品ID, 商品名稱, 價格, 庫存 FROM 商品表 WHERE 商家ID商家ID; using (SqlConnection conn new SqlConnection(connStr)) { using (SqlDataAdapter da new SqlDataAdapter(sql, conn)) { da.SelectCommand.Parameters.AddWithValue(商家ID, currentUserId); DataTable dt new DataTable(); da.Fill(dt); dgvProducts.DataSource dt; } } }SqlDataAdapter 扮演的是數(shù)據(jù)搬運工的角色它先執(zhí)行 SQL 查出結(jié)果再把結(jié)果填充進內(nèi)存里的 DataTable最后通過設(shè)置 DataSource 屬性一次性把整張表顯示在 DataGridView 上。注意 DataSource 賦的是 DataTable 而不是 SqlDataReader因為 DataGridView 需要數(shù)據(jù)源支持隨機訪問而 DataReader 是只進只讀的流式數(shù)據(jù)兩者綁定會直接報錯。5. 避坑指南從打開解決方案到跑通全流程五個典型問題5.1 提示“在建立與服務(wù)器的連接時出錯。與 SQL Server 建立連接時發(fā)生了與網(wǎng)絡(luò)相關(guān)或特定實例的錯誤”現(xiàn)象F5 運行后彈窗報錯錯誤信息里提到“provider: SQL Network Interfaces”。原因基本是 App.config 里的 Data Source 指向的實例名不對或者 SQL Server 服務(wù)沒啟動。最有效的檢查方式是打開 SSMS 嘗試連接本機數(shù)據(jù)庫如果 SSMS 能連上而程序連不上就是連接字符串的問題如果 SSMS 也連不上先去 Windows 服務(wù)管理器里確認 SQL Server 服務(wù)是否在運行。解決把 Data Source 換成 SSMS 登錄窗口顯示的完整服務(wù)器名稱。5.2 附加數(shù)據(jù)庫時提示“無法為數(shù)據(jù)庫分配新頁面因為文件組已滿”現(xiàn)象在 SSMS 里附加數(shù)據(jù)庫文件時報錯或者運行一段時間后寫入數(shù)據(jù)失敗。這個問題的隱蔽之處在于它不一定發(fā)生在附加時刻也可能是數(shù)據(jù)庫文件所在的磁盤空間不足。SQL Server 2019 默認的數(shù)據(jù)庫文件 .mdf 容量耗盡且設(shè)置為固定容量時就會報這個錯。解決右鍵數(shù)據(jù)庫 → 屬性 → 文件 → 將“自動增長”改為“按百分比增長無限制”或者直接清理磁盤空間。課設(shè)期間數(shù)據(jù)量不大出現(xiàn)這個報錯大概率是磁盤滿了。5.3 打開窗體時提示“找不到資源文件”現(xiàn)象編譯通過但運行到某個窗體時拋異常提示找不到 .resx 中引用的資源。常見原因是把項目文件夾移動了位置導(dǎo)致資源文件路徑失效。這個項目里登錄界面和注冊界面都用到了圖片資源這些圖片在 Resources 文件夾下。建議不要移動資源包的目錄結(jié)構(gòu)保持解壓后的原始層級。如果已經(jīng)移動了右鍵 resx 文件 → 重新加載再檢查圖片文件是否被誤刪。5.4 界面中文顯示亂碼現(xiàn)象窗體上的中文標簽或按鈕文字顯示為菱形問號。原因通常是系統(tǒng)區(qū)域設(shè)置不是中文Windows 的非 Unicode 程序語言設(shè)置不匹配。解決控制面板 → 區(qū)域 → 管理 → 更改系統(tǒng)區(qū)域設(shè)置 → 勾選 Beta 版 UTF-8 或改為中文簡體。對于數(shù)據(jù)庫里查出來的中文亂碼則要考慮 SQL Server 排序規(guī)則SQL Server 2019 默認排序規(guī)則 Chinese_PRC_CI_AS 一般不會出問題。5.5 注冊后無法登錄提示用戶名或密碼錯誤現(xiàn)象注冊界面提示注冊成功但回到登錄界面輸入同樣賬號密碼卻報錯。這是最典型的課設(shè)翻車點原因有兩個一是注冊時密碼框里多了空格登錄時 Trim() 去掉了而注冊時沒去掉二是注冊和登錄查詢的不是同一張表——注冊寫入了客戶表登錄卻查了商家表。解決檢查注冊和登錄代碼里操作的表名是否一致同時在所有文本框取值的入口統(tǒng)一加 Trim() 去空格處理。6. 把課設(shè)從“能跑”變“能答辯”三個值得加的功能點先確認一個殘酷事實課設(shè)答辯時老師看的不只是界面好不好看更重要的是你的代碼有沒有“設(shè)計感”。這個資源的界面完成度已經(jīng)很高但如果你想讓成績再上一個檔次我建議在現(xiàn)有基礎(chǔ)上加三個功能點每個的工作量都在一晚上以內(nèi)。第一把訂單狀態(tài)的判斷邏輯封裝成存儲過程?,F(xiàn)在項目里修改訂單狀態(tài)的代碼大概率是直接拼 UPDATE 語句。用存儲過程封裝的好處是狀態(tài)流轉(zhuǎn)的邏輯收斂在數(shù)據(jù)庫端C# 代碼只負責(zé)調(diào)用答辯時老師問“訂單狀態(tài)怎么保證不跳變”你直接展示存儲過程里的 CASE 判斷。CREATE PROCEDURE usp_UpdateOrderStatus OrderID INT, NewStatus INT AS BEGIN UPDATE 訂單表 SET 訂單狀態(tài) NewStatus WHERE 訂單ID OrderID ENDC# 端調(diào)用時用 SqlCommand 指定 CommandType.StoredProcedure然后 AddWithValue 傳參即可。這個小改動會讓你的代碼明顯比同組同學(xué)“高級”。第二給 DataGridView 加一個明細展示。現(xiàn)在商品列表加載后雙擊行大概率沒有反應(yīng)。你可以給 DataGridView 注冊 CellDoubleClick 事件彈出一個小窗體展示該商品的銷量或者該訂單的明細項。這個功能不強但對答辯很有效——它是“主從表聯(lián)動”的直接演示數(shù)據(jù)庫課設(shè)最看重的就是表間關(guān)聯(lián)。第三把密碼改成哈希存儲。現(xiàn)在注冊表里存的還是明文密碼雖然課設(shè)夠用但你可以在注冊代碼里加一行 SHA256 哈希計算登錄時對輸入密碼做同樣處理再比較。改動量極小但老師在答辯時問“安全性怎么考慮”時你至少有話可答而且還能原理解釋清楚。說到底數(shù)據(jù)庫課設(shè)的核心競爭力不是“我把界面畫得多好看”而是“我理解表與表之間的關(guān)系并且能在代碼里把這種關(guān)系正確地表達出來”。從那次以后我每次做類似的 C# SQL Server 課設(shè)都會強制自己先畫一遍實體關(guān)系草圖再去寫任何代碼這個習(xí)慣讓我的課程設(shè)計再沒翻過車。希望這份拆解能幫到你。本文還有配套的精品資源點擊獲取