【Side Project】 点菜单功能实作 - 资料库新增餐点清单

写到资料库这部分,就让我想起一个小故事...

某天客户一把鼻涕一把眼泪地打电话跟我说
客户: 我们要结帐了,可是有些单子里面的项目有少怎麽办?
这不查不打紧,一查才发现,客户公司有一阵子网路不稳定,
转资料的时候,常常转到一半网路挂掉,导致某些时段的单子的资料只转了一半。
看完资料後我也只想说.....凉拌炒鸡蛋,愈炒愈完蛋。

很多刚开始做开发的新人常常会将SQL语法拆开来,很单纯的一个命令一个命令送,
导致我们很难去判别,每一笔(交易)资料是否完整。
若想解决这个问题,我们可以透过资料库ACID特性中的原子性(Atomicity),
来达到确保每笔资料的完整。

新建 Data Class

建立需要与资料库的Table相对应的Class
https://ithelp.ithome.com.tw/upload/images/20210930/20115941iasVR1bsS9.jpg
Menulistb.cs

public class Menulistb
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public long Uid { get; set; }
        public long H_uid { get; set; }
        public string Item { get; set; }
        public int Price { get; set; }
        public int Count { get; set; }
    }

Menulisth.cs

public class Menulisth
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public long Uid { get; set; }
        public string Formnum { get; set; }
        [SugarColumn(IsOnlyIgnoreInsert = true)]
        public int Createtime { get; set; }
    }

这边要注意Createtime上给的属性**[SugarColumn(IsOnlyIgnoreInsert = true)]**
因为我们之後会直接从资料库给这个栏位default值,所以需要设立这个属性。

资料库栏位设定预设值

  1. 开启SSMS
  2. 输入SQL语法
  ALTER TABLE [dbo].[menulisth]
  ADD CONSTRAINT DF_Menulisth_Createtime
  DEFAULT CURRENT_TIMESTAMP FOR [createtime]

https://ithelp.ithome.com.tw/upload/images/20210930/20115941IbInfV62FM.jpg
这样每当我们新增一笔资料的时候,就会自动把当下时间带入到createtime里面。

接收前台的资料

上一篇中已经把资料从前端送到後端来了,
我们接着把传过来的资料处理一下转成对应的object。
1.将 传过来的data 转成 object

Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);

从Json转成Object 无非就四样:

  1. Dictionary( key,value 类)
  2. List(清单类)
  3. base type (基本资料型态)
  4. Data Class (自订类)

稍微注意一下资料的结构就会转了。
2. 把刚刚上面那段加入我们後台处理问题的function中 CreateOrder()

public ActionResult CreateOrder(string data,string phone)
        {
        // 表头部分资料
             var menulisth = new Menulisth()
            {
                Formnum = phone
            };
            Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);
            return Ok();
        }

写入资料库

  1. 建立资料库连线
//连线设定
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                //连线字串
                ConnectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WebMenu;user id=webmenu;password=xxxxxxxx;Integrated Security=False",
                DbType = DbType.SqlServer,//连线类型
                IsAutoCloseConnection = true //自动关闭连线
            });
  1. try...catch包起来我们等等要写入资料库的基本框架
try
            {
                
                //当执行时,触发事件
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//查看SQL语法
                };
                db.BeginTran();
                // dosomething
                db.CommitTran();
            }
            catch 
            {
                db.RollbackTran();//rollback
                throw;
            }

当我们资料出问题的时候会退回到原本的状态,并且打印我们SQL语法的资讯
3. 在 dosomething 的地方写我们要写入资料库的语法

db.BeginTran();
                //写入表头 并 回传表头资料
                menulisth = db.Insertable(menulisth).ExecuteReturnEntity();
                //逐笔将表身资料写入
                foreach (var keyvalue in map)
                {
                    var item = keyvalue.Value;
                    Console.WriteLine(item.Uid + " : " + item.Item + " : " + item.Price + " : " + item.Count);
                    item.H_uid = menulisth.Uid;
                    db.Insertable(item).ExecuteCommand();
                }
                
                db.CommitTran();

这样就成功将资料写入我们资料库了。
CreateOrder()中完整程序码:

public ActionResult CreateOrder(string data,string phone)
        {
            var menulisth = new Menulisth()
            {
                Formnum = phone
            };
            Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);
            
            //连线设定
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                //连线字串
                ConnectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WebMenu;user id=webmenu;password=xxxxxxxx;Integrated Security=False",
                DbType = DbType.SqlServer,//连线类型
                IsAutoCloseConnection = true //自动关闭连线
            });
            try
            {
                
                //当执行时,触发事件
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);//查看SQL语法
                };
                db.BeginTran();
                //写入表头 并 回传表头资料
                menulisth = db.Insertable(menulisth).ExecuteReturnEntity();
                //逐笔将表身资料写入
                foreach (var keyvalue in map)
                {
                    var item = keyvalue.Value;
                    Console.WriteLine(item.Uid + " : " + item.Item + " : " + item.Price + " : " + item.Count);
                    item.H_uid = menulisth.Uid;
                    db.Insertable(item).ExecuteCommand();
                }
                
                db.CommitTran();
            }
            catch 
            {
                db.RollbackTran();//rollback
                throw;
            }
            return Ok();
        }
  1. 建立一张餐点
    https://ithelp.ithome.com.tw/upload/images/20210930/20115941d5nFXSx8UU.jpg
  2. 资料库资料
    https://ithelp.ithome.com.tw/upload/images/20210930/20115941yJ4dYn5Vy2.jpg
    https://ithelp.ithome.com.tw/upload/images/20210930/20115941uBJNKBooMS.jpg

结语

我们可以透过 begin tran ... commit tran将所有要完成的指令一次做完,
这样可以保证我们资料每次进入资料库的时候都是完整的。

另外可能有些人会对时间资讯应该要由资料库直接产生好,还是从程序码中产生好的疑问。
这边给一个思考的方向,当程序码成长到上万行,表单变成上千个的时候,
放在程序码中,还是资料库里哪个比较好维护?


<<:  Day29 小孩子才做选择

>>:  [30天 Vue学好学满 DAY30] 总结 & 完赛感言

# Day 9 Cache and TLB Flushing Under Linux (一)

如同 Day1 简介的,这份文件是之前工作中有碰过 cache & TLB 相关的项目,但是...

Day16-Class

前言 昨日我们学习了原型与建构子函式,但这样其实有点不够直觉,尤其是对於有接触过其它物件导向程序的朋...

Day 20. v-bind - Style的绑定

昨天讲了class的绑定,今天换来讲style (ノ◕ヮ◕)ノ*:・゚✧ 绑定Style v-bin...

EC2上的资料库

除了AWS提供预设的RDS, 若觉得使用起来不顺手, 也可以建立虚拟机, 使用安装版的MSSQL资料...

[Day_12]资料储存容器 - 练习题

今天来为大家介绍资料储存容器的练习题, 过程跟解法可能跟大家不太一样还请大家见谅, 那就让我们开始吧...