寫這篇文章之前先吐槽一下,最近換了一個公司,是給一個國企做外包,有兩個月了,感覺這里的氣氛有點不爽,還有點懷念以前的公司。具體聽我說來,這里有幾個團隊,.net,java,手機開發,.net只有6個人,其他團隊都很多人,沒辦法,這個貌似國際慣例了。
用.net在這里開發一個類似展示信息的系統,是航空公司的運營信息,包括飛機,跑道,地勤,機場等。java做的是飛機排班系統,一聽說明白,.net受歧視啊。這個還不是最主要的,我們做的這個系統沒有什么重要的邏輯,無非是展示一下表,圖等,但是項目經理給我們傳達的思想是:他的頭頭是一個非常有“主見”的老大,對這個系統要求很嚴格,不斷的提出各種新的想法,起初用的telerik控件,底層用的本地webservice+ado.net訪問數據,我開始就疑問,這本地的webservice意義何在,還不如直接用ado.net訪問呢,還有telerik控件比asp.net控件好看一些,但是效率不怎么樣,最終系統中幾個重要的頁面很慢,部署到服務器中之后訪問達不到預期的效果。
后來改用mvc+easyui,本來也沒什么,但是要將easyui中的控件包裝成控件,就是直接在cshtml中可以配置,不寫js代碼這樣的,本來mvc也不是很熟,還要包裝成easyui標簽控件,結果項目進展很緩慢。貌似老大們的IT意識很強,這樣做是為了減輕前段程序員的工作量,但是easyui都不熟,包裝談何容易。
總之兩個字:“折騰”。可能這就是國企的特點吧。
吐槽結束,以上的遭遇讓我想起去年給一個大學同學的圖書銷售公司寫的一個小系統,這個主要是為了他們員工使用excel來記錄眾多繁雜的信息,可以說是一個小的erp系統。技術是最簡單易懂的,最直接的,開發速度是比較快的,最后效果是過得去的。在這里跟大家分享一下。
1.需求
主要的模塊如下,需求還是很簡單的,就是一些對象的增刪改查。
1.業務管理,包含圖書,客戶,業務
2.訂單管理,訂單編輯,訂單搜索
3.人事管理,主要是業務員的工作量
4.系統配置,主要是維護圖書銷售的區域和學校
2.UI設計
因為他們主要矛盾是解決excel過大造成的操作困難這種最原始的需求,所以對UI沒有很高的要求,所以本人不才,自己綉花,結果還算過得去,最起碼這個客戶他們沒有說不好看。截圖如下圖1。
圖1
這里看能看到asp.net默認的實例項目的UI設計,我是在它的基礎上做的。每個訂單有多個訂單子項,這個地方添加訂單子項或編輯的時候寫了很多的js,,界面如下圖2
圖2
所有的表格都使用了一樣的樣式,風格是一致的。如下圖3
圖3
3.代碼結構
這里不敢說用到什么架構,只能說代碼結構了。這里采用最常用的三成架構的方式實現功能,可能大家都習以為常了,確實寫了這些年的代碼,無非都是三層架構的變形,或者底層訪問數據使用接口,頂多返回json客戶端用js拼接界面,其他的也沒有什么了。這里簡單地說一下。
可能和你們一樣,也用到了代碼實現工具Codematic,這個工具確實好用,節省了不少時間,並且基本的代碼結構也實現了。如下圖4。
圖4
這個工具已經實現了所有的單表查詢,可惜大部分的邏輯都是需要連接查詢了,要不然關系數據庫就沒什么意思了,所以自己寫的代碼也不少的。
1.數據訪問層
數據訪問層寫了一個動態存儲過程,生成分頁數據,這里沒有把分頁放在控件里或者內存中實現,存過過程每次返回固定條數的數據,這樣減輕數據量,但是犧牲了一部分新能,動態存儲過程每次都執行不同的語句,沒法調試性能。還有一點,這里犧牲了一些靈活性,比如每頁顯示多少航,轉到多少頁。 調用的存儲過程如下:
exec UP_GetRecordByPage @tblName1='Orders', @tblName2='Orders left join MaintainMessage on Orders.MaintainId=MaintainMessage.ID left join Teacher on MaintainMessage.TeacherID=Teacher.ID left join Employee on MaintainMessage.EmployeeID=Employee.ID left join Book on MaintainMessage.BookID=Book.ID left join School on Teacher.SchoolID=School.ID ', @fldName='Orders.*,Teacher.TeacherName,Employee.Name,Book.Price,Book.BookName,MaintainMessage.OrderStructure', @OrderfldName='Orders.ID', @PageSize=20, @PageIndex=1, @IsReCount=1, @OrderType=1, @strWhere=' 1=1 and School.CityID=1', @IsPrint=1
存儲過程生成的select語句如下:
select top 20 Orders.*,Teacher.TeacherName, Employee.Name,Book.Price,Book.BookName, MaintainMessage.OrderStructure from Orders left join MaintainMessage on Orders.MaintainId=MaintainMessage.ID left join Teacher on MaintainMessage.TeacherID=Teacher.ID left join Employee on MaintainMessage.EmployeeID=Employee.ID left join Book on MaintainMessage.BookID=Book.ID left join School on Teacher.SchoolID=School.ID where 1=1 and School.CityID=1 order by Orders.ID desc /*----*/ select count(1) as Total from Orders left join MaintainMessage on Orders.MaintainId=MaintainMessage.ID left join Teacher on MaintainMessage.TeacherID=Teacher.ID left join Employee on MaintainMessage.EmployeeID=Employee.ID left join Book on MaintainMessage.BookID=Book.ID left join School on Teacher.SchoolID=School.ID where 1=1 and School.CityID=1
得到數據之后就是很常見的轉換成實體類了。
2.業務邏輯層就是將數據返回到展現層,頂多有復雜的數據需要再次訪問數據庫。如下在一個方法中兩次訪問數據,需要說的是這種情況如果數據太多會有很多的性能損失,所幸這里數據不多,因為要分頁,每次頂多返回20條。
public List<Erp.Model.Employee> GetEmployeeFerformance(Model.EmpPerformance performance) { List<Erp.Model.Employee> employees = new List<Model.Employee>(); SqlParameter[] parameters = { new SqlParameter("@BeginDate", SqlDbType.DateTime), new SqlParameter("@EndDate", SqlDbType.DateTime) }; parameters[0].Value = performance.BeginDate; parameters[1].Value = performance.EndDate; DataTable table = DbHelperSQL.RunProcedure("sp_GetEmpPerformance" , parameters , "performance").Tables[0]; if (table!=null && table.Rows.Count>0) { for (int i = 0; i < table.Rows.Count; i++) { Erp.Model.Employee employee = new Model.Employee(); employee.ID = Convert.ToInt32(table.Rows[i]["EmployeeID"].ToString()); employee.Name = table.Rows[i]["Name"].ToString(); employee.EmployeePerformance.MaintainMessageNum = Convert.ToInt32(table.Rows[i]["MaintainMessageNum"].ToString()); employee.EmployeePerformance.CommunicateNum = Convert.ToInt32(table.Rows[i]["CommunicateNum"].ToString()); employee.EmployeePerformance.OrdersNum = Convert.ToInt32(table.Rows[i]["OrdersNum"].ToString()); employee.EmployeePerformance.TotalAmount = Convert.ToDecimal(table.Rows[i]["TotalAmount"].ToString()); employee.EmployeePerformance.TotalRebate = Convert.ToDecimal(table.Rows[i]["TotalRebate"].ToString()); SqlParameter[] parametersDetail = { new SqlParameter("@BeginDate", SqlDbType.DateTime), new SqlParameter("@EndDate", SqlDbType.DateTime), new SqlParameter("@EmployeeID", SqlDbType.Int) }; parametersDetail[0].Value = performance.BeginDate; parametersDetail[1].Value = performance.EndDate; parametersDetail[2].Value = employee.ID; DataSet dsPerformanceDetail = DbHelperSQL.RunProcedure("sp_GetEmpPerformanceNumDetail", parametersDetail, "performanceDetail"); if (dsPerformanceDetail != null && dsPerformanceDetail.Tables.Count > 1) { DataTable tbPerformanceDetail = dsPerformanceDetail.Tables[0]; if (tbPerformanceDetail != null && tbPerformanceDetail.Rows.Count > 0) { for (int j = 0; j < tbPerformanceDetail.Rows.Count; j++) { employee.EmployeePerformance.MaintainMessageNumDetail += string.Format("{0}:{1} ", tbPerformanceDetail.Rows[j]["BusinessImportance"].ToString(), tbPerformanceDetail.Rows[j]["number"].ToString()); } } tbPerformanceDetail = dsPerformanceDetail.Tables[1]; if (tbPerformanceDetail != null && tbPerformanceDetail.Rows.Count > 0) { for (int k = 0; k < tbPerformanceDetail.Rows.Count; k++) { employee.EmployeePerformance.CommunicateNumDetail += string.Format("{0}:{1} ", tbPerformanceDetail.Rows[k]["BusinessImportance"].ToString(), tbPerformanceDetail.Rows[k]["number"].ToString()); } } } employees.Add(employee); } } return employees; }
調用存儲過程的實例代碼如下:
public DataTable GetTitleList(int currentPage, out int pages, Erp.Model.Employee employee) { Erp.DAL.PageData pData = new Erp.DAL.PageData(); pData.TblName1 = "a"; pData.TblName2 = "Employee a left join EmployeeType b on a.EmployeeTypeID = b.ID left join Employee c on a.ManagerID=c.ID"; pData.FldName = "a.ID,a.Name,a.UserName,b.TypeName,c.Name as ManagerName,a.Sex,a.Telphone,a.CellPhone,a.QQ,a.Email,a.Statue,a.Remark,a.ManagerID,a.EmployeeTypeID,a.RegionsIDs,a.Password"; pData.OrderFldName = "a.ID"; pData.OrderType = 0; pData.StrWhere = " 1=1 "; pData.PageIndex = currentPage.ToString(); pData.IsPrint = 1; pData.IsReCount = 1; pData.PageSize = "20"; if(employee != null) { if(!string.IsNullOrEmpty(employee.Name)) { pData.StrWhere += " and a.Name like '%" + employee.Name + "%' "; } if(!string.IsNullOrEmpty(employee.Sex)) { pData.StrWhere += " and a.Sex like '%" + employee.Sex + "%' "; } if(!string.IsNullOrEmpty(employee.UserName)) { pData.StrWhere += " and a.UserName like '%" + employee.UserName + "%' "; } if(!string.IsNullOrEmpty(employee.Statue)) { pData.StrWhere += " and a.Statue like '%" + employee.Statue + "%' "; } if(!string.IsNullOrEmpty(employee.Email)) { pData.StrWhere += " and a.Email like '%" + employee.Email + "%' "; } if(!string.IsNullOrEmpty(employee.CellPhone)) { pData.StrWhere += " and a.CellPhone like '%" + employee.CellPhone + "%' "; } if(!string.IsNullOrEmpty(employee.QQ)) { pData.StrWhere += " and a.QQ like '%" + employee.QQ + "%' "; } if(!string.IsNullOrEmpty(employee.Telphone)) { pData.StrWhere += " and a.Telphone like '%" + employee.Telphone + "%' "; } if(employee.EmployeeTypeID > 0) { pData.StrWhere += " and a.EmployeeTypeID = " + employee.EmployeeTypeID.ToString(); } if(employee.ManagerID > 0) { pData.StrWhere += " and a.ManagerID = " + employee.ManagerID.ToString(); } } DataSet dSet = pData.GetPagedData(); pages = 0; if(dSet != null && dSet.Tables != null && dSet.Tables.Count > 0 && dSet.Tables[1] != null && dSet.Tables[1].Rows.Count > 0) { if(!string.IsNullOrEmpty(dSet.Tables[1].Rows[0]["Total"].ToString())) { int items = Convert.ToInt32(dSet.Tables[1].Rows[0]["Total"].ToString()); if(items % Convert.ToInt32(pData.PageSize) == 0) { pages = items / Convert.ToInt32(pData.PageSize); } else { pages = items / Convert.ToInt32(pData.PageSize) + 1; } } } return dSet.Tables[0]; }
3.展現層就更加簡單了,一般都是使用“萬能的repeater”,沒有什么難度。
<asp:Repeater ID="repEmployees" runat="server" OnItemCommand="repEmployees_ItemCommand"> <ItemTemplate> <tr> <td class="r"> <%#Eval("ID")%> </td> <td> <%#Eval("Name")%> </td> <td> <%#Eval("UserName")%> </td> <td> <%#Eval("TypeName")%> </td> <td> <%#Eval("ManagerName")%> </td> <td> <%#Eval("Sex")%> </td> <td> <%#Eval("Telphone")%> </td> <td> <%#Eval("CellPhone")%> </td> <td> <%#Eval("QQ")%> </td> <td> <%#Eval("Email")%> </td> <td> <%#Eval("Statue")%> </td> <td> <%#Eval("Remark")%> </td> <td> <asp:HiddenField ID="hidManagerID" runat="server" Value='<%#Eval("ManagerID") %>' /> <asp:HiddenField ID="hidEmployeeTypeID" runat="server" Value='<%#Eval("EmployeeTypeID") %>' /> <asp:HiddenField ID="hidRegionsIDs" runat="server" Value='<%#Eval("RegionsIDs") %>' /> <asp:HiddenField ID="hidPassword" runat="server" Value='<%#Eval("Password") %>' /> <asp:LinkButton ID="linEdit" runat="server" Style="padding: 0px;" CommandName="select" CommandArgument='<%#Eval("ID") %>'>編輯</asp:LinkButton> </td> </tr> </ItemTemplate> </asp:Repeater>
4.總結
這個小項目沒有什么出彩的地方,如果大家有用得到類似的,歡迎來聯系我。歡迎大家來怕轉。