2011-02-14 59 views
10

这是一个非常模糊/主观的问题。我想知道这是否是使用ajax调用向/从浏览器发送/检索数据的最佳方式。在后端web服务上,我想使用实体框架。以下是两个示例函数。如何改善实体框架和Javascript交互

“最好”的标准是编写代码的速度,可读代码和可靠的体系结构。

感谢您的任何意见和建议和意见。

获取函数

[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; 
    } 
} 
+0

为什么你有单独的`AjaxEmployee`类?它是你的“员工”实体的投影吗? – 2011-02-14 02:34:12

+0

单独的类,是发送到JavaScript时更好地序列化为JSON。由于Employee和Time_Off记录之间存在关系,所以序列化不会按照以下内容正确执行:http://mytechworld.officeacuity.com/?p=577 – Sam 2011-02-14 15:13:30

回答

9

有一些改进。

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(); 

其中WithIdIQueryable<Employee>扩展方法,它根据提供的员工ID过滤查询。这允许从存储库/ DAL中去除过滤/业务逻辑。它应该放在你的域模型中,这样你就可以拥有一个流畅的API来通过你的ORM查询你的域实体。

当你通过主键检索一个实体,你应该总是使用SingleOrDefault()Single(),从未FirstOrDefault()First()。如果它是主键 - 应该只有一个主键 - 所以如果存在多个主键,则应该抛出异常,这就是SingleOrDefault()所做的。正如@Shiraz提到的那样 - 您的FirstOrDefault()会使下面的查询崩溃。当您使用<First/Single>OrDefault()时,您总是需要空检查。

可以对您的Get方法进行相同的改进。

总的来说,你的代码没有任何功能上的错误 - 它只需要微妙的改进,空检查和异常处理。

我强烈建议的唯一功能改进是将您的Web服务代码重构为通用存储库。由于代码非常简单,可以在任何实体中重复使用。 Web服务不应该关心事务,主键或EF逻辑。它甚至不应该引用EF DLL。将此逻辑封装在存储库后面并将持久性逻辑委托给此处(当然,通过接口)。

在做出上述改变之后,您的Web服务方法应该每行不超过5-7行代码。

你的网络服务中有太多的智能 - 它应该是愚蠢的和持续的无知。

3

我发现,它通常是一个非常糟糕的主意,试图直接用我的实体数据合同。这是可能的,并且在某些情况下工作正常,但是随时我的对象模型变得有点复杂时,我开始不得不以我不想要的方式担心对象图。

取而代之的是,这与客户端无关,但它同样适用于JS客户端,我尝试将数据合约类视为纯数据卡车(DTO),而EF中完全没有映射。这些类只是他传递来的文档,如果你愿意的话。他们可能会翻译成我的模型中的命令,或者他们可能会用来填充查询或其他任何内容,但它们本身不是实体。

这个我觉得很简单。当你第一次写一个简单的服务时,它可能会感觉更多的代码,但是在整个生命周期中,它使事情变得更加可维护。

就在旁注中,您还应该考虑将您的责任分开一点。 Web服务类不应该有直接创建数据上下文的责任,它应该依赖于为你处理所有东西(并根据需要应用事务等)的DAO或存储库接口(或域服务)。

0

您的get方法可能会崩溃。

如果该行返回null:

var emp = results.FirstOrDefault(); 

那么这条线将一个空引用异常崩溃:

where item2.Employee_ID == emp.Employee_ID 

我也会把一些尝试catch块中有错误的记录。