一个asp.net小项目总结
写这篇文章之前先吐槽一下,最近换了一个公司,是给一个国企做外包,有两个月了,感觉这里的气氛有点不爽,还有点怀念以前的公司。具体听我说来,这里有几个团队,.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.总结
这个小项目没有什么出彩的地方,如果大家有用得到类似的,欢迎来联系我。欢迎大家来怕转。
作者:Tyler Ning
出处:http://www.cnblogs.com/tylerdonet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,请微信联系冬天里的一把火