標籤:過程 insert summary color 命名 主鍵 刪除 c項目 serialize
一線程式員和 sa 總是相恨相殺,這話確實不假,吐槽這裡就不多講,項目快開發完的時候,讓之前各個模組的增刪改操作全部都先放入對應的暫存資料表(增加一狀態列位Status,來表示增、刪、改)中,然後在主管允許存取介面允許存取之後,資料才算真正入庫。sa 輕輕一句話,整個項目幾乎從頭到尾要改一遍。雖然已不是第一次做此事。但著實還是費了一番氣力。期間遇到了不少問題很值得記錄。
流程大致如上,第一排是原邏輯,第二排是增加主管允許存取的新邏輯(隨手畫的,比較簡陋)
原項目中涉及到,多表主外鍵關係,新增範本功能等較為複雜的邏輯。這裡在後面會做一個大致的流程說明
由於各表的欄位,主外鍵關係不同,所以第一次開發時,均是對維護的每個表(功能)建立對應的Biz(業務處理類)來實現增刪改查。
新需求要求使用者對資料的刪、改、查操作均 添加到對應的temp表中,如 表A 欄位 B,C,D -對應- 暫存資料表TempA 欄位 B,C,D,Status
1 .操作某表資料
在對錶進行 新增、修改、刪除 操作之前,都要先到暫存資料表中去撈取,看是否該資料已存在待主管允許存取的暫存資料表中,這裡可直接寫一個公用方法,傳表名 和 主鍵即可
(PS:新增、修改傳入的是一筆主索引值,故需要封裝,兩側加單引號,刪除的話,前台ajax提交時,已經添加過單引號)
public bool IsExistTemp(string tbname, string strtablekey,string operatype) { try { //in操作 新增、修改傳入值需要封裝下 if (operatype != "D") { strtablekey = "‘" + strtablekey + "‘"; } string strsql = "SELECT COUNT(*) FROM " + tbname + " AS a WHERE a.TableKey IN(" + strtablekey + ") "; int row = (int)base.ExecuteScalar(strsql); return row > 0; } catch (Exception e) { return false; } }
①執行新增、修改
新增介面點擊確定、和修改介面點擊確定 均是對一筆資料資料操作,直接採用Ajax的 方式,調用serializeArray()方法提交整個表單的資料 ,到Action中
對新增來說: A 判斷新增的這筆資料是否已在表中存在 B 判斷該筆資料是否已存在待主管允許存取的暫存資料表中 C 將該資料添加至暫存資料表中
對修改來說: A 第一次跳轉至修改介面之前,先去該筆資料是否已存在待主管允許存取的暫存資料表中,若在,修改介面給出提示,儲存按鈕為灰色不可點擊
B 將該資料添加至暫存資料表中
相對前期判斷沒什麼好說的,至於某筆資料檢核無誤後(通過A、B)條件, 添加至暫存資料表中,新增、刪除的邏輯代碼是一樣的,一遍即可
②執行刪除
查詢結果介面,可勾選多筆資料,進行刪除操作,這就意味著需要往暫存資料表中添加多筆資料。前台Ajax提交時,先遍曆複選框,然後將複選框勾選狀態所在行的主鍵Key,進行封裝再傳遞。
前面的部落格中,我做的處理是迴圈刪除,用List<string> 接受傳來的主鍵集合,然後遍曆該集合, 比較費事,這裡我直接將主鍵進行拼接,作為一個string字串來進行傳遞
KeyList.push(tabkey);
tablekeys = "‘" + KeyList.join("‘,‘") + "‘";
這樣後台Action中接收的樣式就是 ‘‘k1‘,‘k2‘,‘k3‘...‘
後台接收到主鍵拼接的字串之後,傳入 原表名稱,目的表名稱,主索引值,目的表的Status欄位值 四個參數即可,公用方法如下
/// <summary> /// 新需求-刪除(為主管允許存取而寫),實則將A表數據寫到B表中 /// </summary> /// <param name="tbname">原表</param> /// <param name="tbnameTo">目的表</param> /// <param name="tablekeys">聯合主鍵</param> /// <param name="status">操作狀態(D:刪除)</param> /// <returns></returns> public bool Delete_AddTemp(string tbname, string tbnameTo, string tablekeys, char status) { try { string strsql = @"INSERT INTO " + tbnameTo + " SELECT *,‘" + status + "‘ FROM " + tbname + " WHERE TableKey IN (" + tablekeys + ")"; //執行Sql,返回影響的行數,並判斷 return base.ExecuteNonQuery(strsql) > 0; } catch (Exception ex) { return false; } }
寫到這裡,關於對原表的操作,就完成了,邏輯細分下來,實際上沒有多少代碼量
2. 主管允許存取介面的查詢
前面使用者操作多個表之後,將資料寫入到對應的Temp表中,來等待主管審批(允許存取\刪除)。 這裡查詢介面寫一下拉式清單,選中某表,點擊查詢,後台返回對應的視圖來顯示該暫存資料表資料,為了更好的拓展以及後期的維護,這裡對應的視圖目錄,每一個表寫一個視圖,這樣控制器在查詢Action方法中,根據前台傳的表名,返回對應表所在的View即可。查詢操作比較基礎,沒什麼值得寫的。寥寥幾句,敘述清楚流程即可。
3. 主管允許存取
主管允許存取這裡邏輯較為複雜,遇到了不少問題,剛開始就寫一預存程序,命名為sp_TableName,裡面嵌入一事務,將某表的多個語句(增、刪、改)寫在一起,執行成功就提交事務,失敗就復原。這樣的思路的話,只需要一個表對應一個預存程序,調用時傳入預存程序名, 和主鍵。於是乎,洋洋洒洒的將預存程序寫完。極度簡化後代碼如下
--刪除 DELETE FROM A WHERE TableKey IN (SELECT TableKey FROM tempA WHERE sFlag = ‘D‘ AND TableKey IN(@str)) --清空臨時資源表 DELETE FROM tempZT_SysConfig_Master WHERE TableKey IN (@str);
結果調用預存程序時候總是執行失敗,在T-sql中執行預存程序是成功的,但是在MVC中調用預存程序時,老是執行返回影響行數為0,後來查看日誌後發現,傳入的主鍵參數在SQL中解析時有問題,這裡主鍵是聯合鍵,格式為 A,B ,MVC中調用時傳入的主鍵為
string keys ="‘‘a1,b1‘,‘a2,b2‘,‘a3,b3‘‘";
執行到SQL中時,解析的@str 並不是 ‘‘a1,b1‘,‘a2,b2‘,‘a3,b3‘‘ ,在開啟了不少web介面之後,找了一種解決方案 就是用 exec(‘‘) 將sql語句包裹起來,如下
EXEC(‘ --刪除 DELETE FROM A WHERE TableKey IN (SELECT TableKey FROM tempA WHERE sFlag = ‘‘D‘‘ AND TableKey IN(‘+@str+‘)) --清空臨時資源表 DELETE FROM tempZT_SysConfig_Master WHERE TableKey IN (‘+@str+‘); ‘)
總算解決了,後來在測試中又遇到了新問題,主外鍵約束,由於原表中存在主外鍵約束,而對應的暫存資料表Temp是沒有主外鍵關係的,如果有的話,主次顛倒不少,邏輯就更加複雜而且無效
從表新增約束
假如某使用者登入系統後對主表A增加幾筆資料,然後在從表B中添加了幾筆對應的資料,當主管允許存取暫存資料表B的這筆資料時,由於主管還沒允許存取暫存資料表A的這筆資料,所以執行時就會異常。
這裡只需要給一提示,請先允許存取主表中的新增資料即可,查詢是否有從表新增約束的核心sql 如下,判斷傳回值是否大於0 即可。
SELECT COUNT(a.TableKey) FROM(SELECT distinct b.TableKey FROM tempMainA AS aINNER JOIN tempMinorA AS b ON a.s1 = b.s1 AND a.s2 = b.s2 ) AS aWHERE a.TableKey IN(@tablekeys)
主表刪除約束
假如某使用者登入系統後對主表刪除幾筆資料,當主管允許存取暫存資料表此批資料時,調用預存程序執行到對應的刪除T-SQl語句時,由於外鍵約束,從表對應的資料還在,所以就會報異常
這裡主需要在預存程序中刪除語句的sql上面,寫入刪除從表的sql即可。不過這裡由於表的特殊性,在擷取從表主鍵時著實下了不少功夫,刪除從表的SQL如下:
--刪除從表DELETE FROM Minor WHERE TableKey IN( SELECT a.TableKey FROM Minor AS a WHERE substring(a.TableKey,1,len(a.TableKey) - CHARINDEX(‘‘,‘‘,reverse(a.TableKey))) IN( SELECT TableKey FROM tempMain WHERE status = ‘D‘ AND TableKey IN(‘[email protected]+‘)) )
從表聯合主鍵為 ‘a1,a2,a3‘ , 主表聯合主鍵為 ‘a1,a2‘ ,所以先撈取執行刪除操作的主表的聯合主鍵 tablekey(第三行),然後通過截取從表的聯合主鍵Tablekey in (第二行)得到從表需要刪除的TableKey,最後執行刪除從表操作.
4. 主管刪除
關於主管刪除 ,其實就是清空Temp表的記錄。對於允許存取來說,其邏輯就相當的簡單,沒有必要去迴圈刪除,直接如上操作,後台接收前台傳入主鍵拼接後的string字串和表名,然後在邏輯類中寫入delete的T-sql即可
DELETE FROM " + tbname + " WHERE TableKey IN(" + tablekeys+ ")
執行操作,完成主管刪除
總結:寫到這裡,關於主管允許存取的簡體版本的大致流程已經敘述完了,說白了,允許存取實際上就是將 暫存資料表的資料剪下至原表,沒錯,就是剪下,實現剪下操作時,T-SQL的能力要有,自認為我的水平遠不如老大,原項目中本來我就寫有對資料的刪、改、增操作。所以我第一次的思路是主管允許存取時,一筆一筆的去執行,傳入實體,調用原始的刪、改、增方法。這樣效率低不說,傳入實體的邏輯寫起來也相當費勁。最後在老大手把手的教授下,通過預存程序可允許存取暫存資料表中所有勾選的資料,著實提高了效率。
---市人皆大笑,舉手揶揄之
關於MVC項目中的主管允許存取