感谢任何意见和建议和意见.
[WebMethod] public AjaxEmployee EmployeeGetById(int employeeID,bool getTimeOff) { using (Time_TrackerEntities ctx = new Time_TrackerEntities()) { var results = from item in ctx.Employees where item.ID == employeeID orderby item.Last_Name select new AjaxEmployee { ID = item.ID,Employee_ID = item.Employee_ID,First_Name = item.First_Name,Middle_Name = item.Middle_Name,Last_Name = item.Last_Name,Supervisor_ID = item.Supervisor_ID,Active = item.Active,Is_Supervisor = item.Is_Supervisor }; var emp = results.FirstOrDefault(); if (getTimeOff) { var results2 = from item2 in ctx.Time_Off where item2.Employee_ID == emp.Employee_ID select new AjaxTime_Off { ID = item2.ID,Employee_ID = item2.Employee_ID,Date_Off = item2.Date_Off,Hours = item2.Hours }; emp.Time_Off = results2.ToList<AjaxTime_Off>(); } return emp; } }
保存功能
[WebMethod] public bool EmployeeSave(AjaxEmployee emp) { using (Time_TrackerEntities ctx = new Time_TrackerEntities()) { var results = from item in ctx.Employees where item.ID == emp.ID select item; var myEmp = results.FirstOrDefault(); if (myEmp == null) { myEmp = new Employee(); ctx.Employees.AddObject(myEmp); } myEmp.Employee_ID = emp.Employee_ID; myEmp.First_Name = emp.First_Name; myEmp.Middle_Name = emp.Middle_Name; myEmp.Last_Name = emp.Last_Name; myEmp.Supervisor_ID = emp.Supervisor_ID; myEmp.Active = emp.Active; myEmp.Is_Supervisor = emp.Is_Supervisor; return ctx.SaveChanges() > 0; } }
解决方法
Save()方法 – 不要从左到右复制,使用EF内置逻辑
而不是这样:
myEmp.Employee_ID = emp.Employee_ID; myEmp.First_Name = emp.First_Name; myEmp.Middle_Name = emp.Middle_Name; myEmp.Last_Name = emp.Last_Name; myEmp.Supervisor_ID = emp.Supervisor_ID; myEmp.Active = emp.Active; myEmp.Is_Supervisor = emp.Is_Supervisor;
你可以这样做:
ctx.Employees.ApplyCurrentValues(EMP).
这样做是在图中找到具有相同键的实体(由于您刚刚使用FirstOrDefault()检索它),并且使用您传入的实体来覆盖标量值 – 这正是您的这样做.
所以你的7行变为1,加上如果你添加任何额外的标量属性 – 你不必重构你的代码.只要记住 – 只适用于标量属性,而不是导航属性.
为什么要构建主键检索的查询?只需使用谓词到SingleOrDefault()
而不是这样:
var results = from item in ctx.Employees where item.ID == emp.ID select item; var myEmp = results.FirstOrDefault();
做这个:
var myEmp = ctx.Employees.SingleOrDefault(x => x.ID == emp.Id);
或者甚至更好,使用管道/过滤器技术:
var myEmp = ctx.Employees.WithId(emp.Id).SingleOrDefault();
WhereId是一个IQueryable< Employee>扩展方法,根据提供的员工ID过滤查询.这允许从存储库/ DAL中去除过滤/业务逻辑.它应该进入您的域模型,所以您可以有一个很好的流畅的API通过您的ORM查询您的域实体.
当您通过主键检索实体时,您应始终使用SingleOrDefault()或Single(),不要使用FirstOrDefault()或First().如果它是一个主键 – 应该只有其中之一,所以如果存在多个,那么应该抛出异常,这是SingleOrDefault()所做的.而且@Shiraz提到 – 你的FirstOrDefault()将会崩溃下面的查询.当您使用< First / Single> OrDefault()时,您始终需要进行空检查.
您可以对Get方法进行相同的改进.
总的来说,你的代码没有什么功能上的错误 – 它只需要微妙的改进,空检查和异常处理.
我强烈推荐的唯一功能改进是将您的Web服务代码重定向到通用存储库.由于代码非常简单,可以跨任何实体重用. Web服务不应该涉及交易,主键或EF逻辑.它甚至不应该引用EF DLL.将这个逻辑封装在存储库之后,并将持久性逻辑委托给(通过当然的接口).
你的Web服务中有太多的智能 – 它应该是愚蠢的,持之以恒的.