写到资料库这部分,就让我想起一个小故事...
某天客户一把鼻涕一把眼泪地打电话跟我说
客户: 我们要结帐了,可是有些单子里面的项目有少怎麽办?
这不查不打紧,一查才发现,客户公司有一阵子网路不稳定,
转资料的时候,常常转到一半网路挂掉,导致某些时段的单子的资料只转了一半。
看完资料後我也只想说.....凉拌炒鸡蛋,愈炒愈完蛋。
很多刚开始做开发的新人常常会将SQL语法拆开来,很单纯的一个命令一个命令送,
导致我们很难去判别,每一笔(交易)资料是否完整。
若想解决这个问题,我们可以透过资料库ACID特性中的原子性(Atomicity),
来达到确保每笔资料的完整。
建立需要与资料库的Table相对应的Class
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值,所以需要设立这个属性。
ALTER TABLE [dbo].[menulisth]
ADD CONSTRAINT DF_Menulisth_Createtime
DEFAULT CURRENT_TIMESTAMP FOR [createtime]
这样每当我们新增一笔资料的时候,就会自动把当下时间带入到createtime
里面。
上一篇中已经把资料从前端送到後端来了,
我们接着把传过来的资料处理一下转成对应的object。
1.将 传过来的data 转成 object
Dictionary<string, Menulistb> map = JsonConvert.DeserializeObject<Dictionary<string, Menulistb>>(data);
从Json转成Object 无非就四样:
稍微注意一下资料的结构就会转了。
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();
}
//连线设定
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();
// 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();
}
我们可以透过 begin tran
... commit tran
将所有要完成的指令一次做完,
这样可以保证我们资料每次进入资料库的时候都是完整的。
另外可能有些人会对时间资讯应该要由资料库直接产生好,还是从程序码中产生好的疑问。
这边给一个思考的方向,当程序码成长到上万行,表单变成上千个的时候,
放在程序码中,还是资料库里哪个比较好维护?
>>: [30天 Vue学好学满 DAY30] 总结 & 完赛感言
如同 Day1 简介的,这份文件是之前工作中有碰过 cache & TLB 相关的项目,但是...
前言 昨日我们学习了原型与建构子函式,但这样其实有点不够直觉,尤其是对於有接触过其它物件导向程序的朋...
昨天讲了class的绑定,今天换来讲style (ノ◕ヮ◕)ノ*:・゚✧ 绑定Style v-bin...
除了AWS提供预设的RDS, 若觉得使用起来不顺手, 也可以建立虚拟机, 使用安装版的MSSQL资料...
今天来为大家介绍资料储存容器的练习题, 过程跟解法可能跟大家不太一样还请大家见谅, 那就让我们开始吧...