最近剛加入GUT項目,學習了很多其他同事寫的代碼,感覺受益匪淺。
在GUT項目中,經常會碰到這樣一個問題:動態生成表格,包括從數據庫中讀取數據,並綁定在表格中,以及從在頁面上通過jQuery新增刪除表格。如下所示:
在實現過程中,開發人員經常采用如下方式來實現:
1) 在前台,通過js生成表格行的html字符串,然后通過jquery的after方法加到表格底部。
2) 在后台,讀取數據庫,然后生成表格的html字符串,然后傳遞給前台渲染
3) 這樣做的好處,主要是可以實現無刷新的操作表格的效果
這種實現方式存在如下些問題(當然,個人意見,僅作技術交流^_^):
1) 代碼重復。前台寫了一遍表格創建的js,后台又寫了一遍
2) 字符串拼接。后台創建時,會大量使用字符串的拼接來實現表格的htnl字符串,不僅影響效率,而且不容易debug。比如少了個引號等,不容易找出來。(關於效率問題,因為字符串在.net中是恆定的,所以如果做很多次字符串的拼接,將造成資料的浪費和效率地下)
3) 綁定表格數據與獲取表格數據要寫很多代碼,假設表格有10列字段,就要寫關於這10列的數據怎么獲取,以及怎么綁定會表格中的。
4) 開發人員經常在.aspx頁面中寫數據庫的訪問操作,這樣也不符合MVC分離關注點的精神。如果項目換成別的數據庫,比如oracle(按照項目的數據量來看,未來不排除換數據庫的可能性),那么屆時開發人員將需要滿項目中數據庫相關的語句來修改。
--------------------------------------分割線------------------------------------------
如前所述,可以從如下幾個思路來思考:
1) 能否只在頁面上編寫一些js腳本,來創造表格,而在后台只是提供要創建表格數據即可。也就是說后台獲取數據,然后交給前台去調用js函數創建表格。這樣就可以避免前后台都寫兩次的問題了。而且也不會在后台用大量的字符串拼接來創建表格的html字符串。
2) 能否換種方式,不要通過字符串拼接的方式來創建表格?比如jquery.html()?
3) 能否提供一種統一的創建表格,綁定表格,獲取表格數據的方法呢?以免每次都要寫那么多代碼來創建表格。
基於上述思路,我開發了一個demo,實現了用較少的代碼動態創建表格,綁定表格數據,獲取表格數據,並保存到數據庫中。而且代碼是可以復用的。
--------------------------------------分割線------------------------------------------
前期准備:
1) 創建數據庫test,添加表person
2) 創建Entities層,DAL層,BLL層
Entities層(通過T4模板自動生成)
using System;
using MyBasicLib;
using MyBasicLib.Data.ORMLiteNew;
namespace ATMB.DCMS.Entities
{
/// <summary>
///
/// </summary>
[Serializable]
[Table(TableName="person" ,KeyName="ID")]
public partial class person:BaseTable
{
/// <summary>
///
/// </summary>
public person()
{
}
#region Public Properties
/// <summary>
///
/// </summary>
public override String ID
{
set ; get ;
}
/// <summary>
///
/// </summary>
public String name
{
set ; get ;
}
/// <summary>
///
/// </summary>
public String age
{
set ; get ;
}
/// <summary>
///
/// </summary>
public String sex
{
set ; get ;
}
/// <summary>
///
/// </summary>
public String location
{
set ; get ;
}
#endregion
}
}
DAL層,實現了新增,批量新增,刪除,獲取所有數據的幾個簡單的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ATMB.DCMS.Entities;
using MyBasicLib.Data.ORMLiteNew;
namespace DAL
{
public class PersonDA
{
public void Add(person p)
{
using (var dc = new DataContext())
{
dc.Insert(p);
dc.SubmitChanges();
}
}
public void Add(List<person> ds)
{
using (var dc = new DataContext())
{
foreach(var p in ds)
{
dc.Insert(p);
}
dc.SubmitChanges();
}
}
public void Delete()
{
using (var dc = new DataContext())
{
dc.Delete<person>(p => !SqlMethods.IsNull(p.ID));
dc.SubmitChanges();
}
}
public List<person> GetList()
{
using (var dc = new DataContext())
{
return dc.GetTable<person>().ToList();
}
}
}
}
BLL層
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ATMB.DCMS.Entities;
using DAL;
namespace BLL
{
public class PersonBLL
{
PersonDA da;
public PersonBLL()
{
da = new PersonDA();
}
public void Add(List<person> ds)
{
da.Delete();
da.Add(ds);
}
public List<person> GetList()
{
return da.GetList();
}
}
}
備注:數據庫底層訪問使用Linq,換成oledb等其他方式只要修改DAL層就可以了。
3) 通過js實現表格的動態創建
第一步:定義表格
這里有幾個地方要注意下:
第一:頁面上添加的表格中,我添加了兩個tr,一個是顯示出來的tr,帶有“新增”的圖標。另一個是隱藏的,用來作為新增的行的模板。這樣,不容易出錯,而且避免通過字符串來創建。
第二:顯示的tr中,設置了一個叫”TargetTR”的class,這個是用來搜索表格的所有行的,后面會用到。
第三,每個td中,新增了一個tag屬性,與數據庫表的實際字段對應,用來自動獲取和綁定表格數據。
第四,tr模板的每個input的id(或者其他需要替換的屬性)都定義為XXX_x,_x后綴是用來替換的。比如新增了一個tr,序號為3,便要替換tr中每個input的_x后綴為_3。諸如此類。
第二步:實現新增和刪除表格行的js方法
ChangeAttr實現如下:
changeAttr主要是實現替換input的帶_x結尾的屬性為具體的序號。
以上實現了在頁面上對表格行的新增和刪除。通過模板的定義,我們無需在js寫新增的tr的html字符串。這樣可以最大可能的減少錯誤發生的可能性。因為字符串的可讀性比較差,debug比較難。
接下來,要實現后台獲取表格數據,然后通過上述的幾個js腳本動態生成表格。
首先介紹下實現的思路
第一步,看下.ashx中的實現
Ashx中的實現很簡單,就是根據前台的請求,進行相應的操作,然后返回結果(json)給前台
第二步:前台通過ajax訪問.ashx,獲取表格數據
Success時,會以json的格式返回表格的數據(比如person的集合),然后前台會解析這個json數據,並創建表格出來。
BindTable的實現很簡單,首先看下共有多少條數據,然后多次調用add_tr方法,添加tr。(因為第一個tr是默認存在的,所以只要調用json.length-1次)
接下來便是該功能的核心了,綁定表格的數據。這里只需要調用一個函數就可以了bindTableValue,其實現如下
這個函數可以實現任意表格的數據綁定。完全可以復用。當然還存在些缺陷。本文最后會作以說明。
以上遍實現了從數據庫獲取值,然后動態繪制表格的過程。整個過程沒有針對特定的表格來實現,所以代碼是可以復用的。這個實現過程還有個好處是:分離關注點。對於表現層(前台,web層),只關心於根據數據來做相應的展現,而不關心數據是怎么來的(來自於sql,還是oracle?采用何種方式)。而BLL層負責根據用戶的請求返回數據。關注於業務邏輯的處理。這樣的實現方式,不會在前台寫任何的sql語句。代碼看起來比較簡潔。
最后,實現將修改后的表格數據保存回數據庫中。這就比較簡單了
當點擊保存時,調用save方法。Save方法中的核心是第一句:
getTableValue的實現為:
這樣,開發人員同樣不用寫任何代碼,便可以實現數據對象的自動獲取。該代碼是可以復用的。
--------------------------------------分割線------------------------------------------
總結:
- 上文以可復用,可擴展,分離關注點的方式實現了表格的動態繪制,數據的自動綁定和自動獲取。而且用戶的代碼量相較以往減少了非常多。
- 自動綁定和獲取的方法還存在些不足,因為當前版本的實現只是基於string類型的。未考慮datetime,bool,int等類型。但是根據分離關注點的原則(或者依賴倒置原則),我們同樣可以將該部分邏輯分離出來,交給專門處理數據類型的類來處理。然后保持原有的邏輯不變。下來我會繼續改進。
- 該方法同樣適用於表單數據的保存和綁定.
- 心得體會:Less Code, Less Copy, More ReUseable, More Flexiable and More OO。