iT邦幫忙

2021 iThome 鐵人賽

DAY 18
2
自我挑戰組

【Side Project】 系列 第 18

【Side Project】 程式碼整理 -Model運用

  • 分享至 

  • xImage
  •  

之前為方便快速了解我們程式完整的功能,
所以把所有的資料都放在Controller裡面。
今天這篇我們來整理一下先前的程式碼,
順便帶大家瞭解一下MVC-Model的功用。

appsettings.json

這是一隻在專案創建時就會有的文件,
在這文件中會存放一些關於系統中的設定。
我們也會在這新增一些系統參數在這邊,供我們系統運行的時候使用。

  1. 打開 appsettings.json 文件
  2. 新增我們的資料庫連線字串
"WebmenuConnectionString":"Server=.\\SQLEXPRESS;Initial Catalog=WebMenu;user id=webmenu;password=xxxxxxxx;Integrated Security=False"

(帳號密碼用自己當初在資料庫設定的密碼)
https://ithelp.ithome.com.tw/upload/images/20211001/20115941oVLrkWh5zm.jpg

3.開啟 HomeController.cs
4.在 建構子時透過 DI 注入 IConfiguration

private IConfiguration _config;

        public HomeController(ILogger<HomeController> logger, IConfiguration config)
        {
            _logger = logger;
            _config = config;
        }

因為在ASP.NET Core 中一開始執行Startup.cs的時候,
就會透過 DI 注入 IConfiguration 組態設定檔內容。
所以我們在撰寫的時候不需要去注意修改Startup.cs

MVC-Model

大家實際運用MVC開發的時候,或多或少都有一些功能分類上的差異。
那這邊對Model處理的業務範圍,用處理資料的地方 簡言概括之,
不管是傳送、接收、或是對資料的運算,我們都會放在Model裡面。

我們這邊分類的方式也很簡單,就是一個畫面配上一個Model,
用來處理data的傳送、接收、運算。

Common.cs

這邊放一些通用的資料處理function()

  1. 我們新增一個檔案 /api/Common.cs
  2. 將Json序列化的程式碼移動到這裡面
public static string Obj2JsonString(object obj)
        {
            return    JsonConvert.SerializeObject(obj);
        }

https://ithelp.ithome.com.tw/upload/images/20211002/20115941w0EgOCQtAS.jpg

Customer.cs

  1. 我們新增一個檔案 /api/CustomerModel.cs
  2. 做一個 Singleton pattern的設計模式
public class Customer
    {
        public static CustomerModel customer
        {
            
             get
            {
                if (mCustomer == null)
                {
                    mCustomer = new CustomerModel();
                }
                return mCustomer;
            }
        }

https://ithelp.ithome.com.tw/upload/images/20211002/20115941nlZfmFiBHg.jpg
這樣的設計方式可以保證只創建單一物件,
並且在系統剛啟動時不直接創建物件,也能加快系統的加載速度。
(不過這邊沒有特別處理異步的問題,有興趣的小夥伴在自行改寫)

  1. 取得資料庫中菜單的程式碼移動到這裡面
public List<Menu> SelectMenu(IConfiguration config)
        {
            //連線設定
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                //連線字串
                ConnectionString = config.GetValue<string>("WebmenuConnectionString"),
                DbType = DbType.SqlServer,//連線類型
                IsAutoCloseConnection = true //自動關閉連線
            });
            //當執行時,觸發事件
            db.Aop.OnLogExecuting = (sql, pars) =>
            {
                Console.WriteLine(sql);//查看SQL語法
            };

            var list = db.Queryable<Menu>().ToList();
            foreach (var menu in list)
            {
                menu.Item = menu.Item.Trim();
                Console.WriteLine(menu.Item);
            }
            return list;
        }
  1. 菜單資料轉成Object
public void CreateOrder(string data, string phone,out Dictionary<string, Menulistb> order_body,out Menulisth order_head)
        {
            order_head = new Menulisth()
            {
                Formnum = phone
            };
            order_body = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);
        }
  1. 將菜單寫入資料庫
public bool insertOrder(IConfiguration config ,Dictionary<string, Menulistb> order_body, Menulisth order_head)
        {
            //連線設定
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = config.GetValue<string>("WebmenuConnectionString"),
                DbType = DbType.SqlServer,//連線類型
                IsAutoCloseConnection = true //自動關閉連線
            });
            try
            {

                //當執行時,觸發事件
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//查看SQL語法
                };
                db.BeginTran();
                //寫入表頭 並 回傳表頭資料
                order_head = db.Insertable(order_head).ExecuteReturnEntity();
                //逐筆將表身資料寫入
                foreach (var keyvalue in order_body)
                {
                    var item = keyvalue.Value;
                    item.H_uid = order_head.Uid;
                    db.Insertable(item).ExecuteCommand();
                }

                db.CommitTran();
            }
            catch
            {
                db.RollbackTran();//rollback
                throw;
            }
            return true;
        }

乾淨的Controller

我們將處理資料的業務轉道model之後,
我們的HomeController.cs不僅瘦身成功,
可讀性也是大幅度上升。

HomeController.cs 裡的Customer():

public IActionResult Customer()
        {
            var customer = CustomerModel.customer;
            var menu_list = customer.SelectMenu(_config);
            string jsonData = Common.Obj2JsonString(menu_list);
            ViewBag.menuData = jsonData;
            return View();
        }

這樣我們就可以非常清晰的看懂程式碼中做的事情:

  1. 取得Model
  2. 取得菜單
  3. 轉成Json String
  4. 攜帶資料回傳

HomeController.cs 裡的CreateOrder():

public ActionResult CreateOrder(string data,string phone)
        {
            var customer = CustomerModel.customer;
            customer.CreateOrder(data, phone, out var order_body,out var order_head);
            customer.insertOrder(_config,order_body, order_head);
            
            return Ok();
        }
  1. 取得Model
  2. 建立菜單
  3. 寫入資料庫

結語

當專案開發到一定程度的時候,適時的回頭去做Code Review是件非常重要的事情。
不然常常專案開發到後面會變得殘破不堪東貼西補的。

一般在外面使用MVC開發時,很常可以看見這種
1個View + 1個Controller + 1個 model的方式
這樣的配置雖然不一定是效率比較好的配置方式,
但在專案中檢索時就相對的方便許多。

有些人在看到

public static string Obj2JsonString(object obj)
        {
            return    JsonConvert.SerializeObject(obj);
        }

會有些疑惑,為什麼要把別人包好的功能在包一層起來?
這樣做主要可以讓Controller與套件解耦合,
當我們要對套件進行更新或是對某些功能做異動的時候,
我們只需要到Model上面進行維護,而不需要連Controller一起更動。

可能有些萌新還會問為什麼不把config直接存在model裡面使用,
這樣不就不需要一直傳參數了嗎?
(設計成 function()function(arg1,arg2)的區別)
當然,這種設計方式是完全沒問題的。
只是這樣的設計方式我們在閱讀程式碼的時候,
會比較難找到資料的流向。
比較簡單的分法就是:

  1. 內部使用的function()就存參數在Class內(privateprotected)
  2. 外部呼叫的function(arg)就用傳參數的方式(publicdefault)

簡單版:

  1. 定期Code Review
  2. 1個View + 1個Controller + 1個 model配置方式
  3. Controller與套件解藕
  4. 開發時須注意資料流向及可讀性問題

有細心的小夥伴應該會發現,我之前menu 跟 order 傻傻分不清楚,
導致命名的時候有一點奇怪。因為不影響功能,所以就將就一下吧。


上一篇
【Side Project】 點菜單功能實作 - 資料庫新增餐點清單
下一篇
【Side Project】 訂單清單 - 畫面設計
系列文
【Side Project】 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言