Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何改进实体框架和Javascript交互_C#_.net_Ajax_Entity Framework - Fatal编程技术网

C# 如何改进实体框架和Javascript交互

C# 如何改进实体框架和Javascript交互,c#,.net,ajax,entity-framework,C#,.net,Ajax,Entity Framework,这是一个相当模糊/主观的问题。我想知道这是否是使用ajax调用向浏览器发送/检索数据的最佳方式。在后端webservice上,我想使用实体框架。下面是两个示例函数 “最佳”的标准是编写代码的速度、可读代码和健壮的体系结构 感谢您的反馈、建议和评论 获取函数 [WebMethod] public AjaxEmployee EmployeeGetById(int employeeID, bool getTimeOff) { using (Time_TrackerEntities ctx =

这是一个相当模糊/主观的问题。我想知道这是否是使用ajax调用向浏览器发送/检索数据的最佳方式。在后端webservice上,我想使用实体框架。下面是两个示例函数

“最佳”的标准是编写代码的速度、可读代码和健壮的体系结构

感谢您的反馈、建议和评论

获取函数

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

我发现在数据契约中直接使用我的实体通常是一个非常糟糕的想法。这是可能的,并且在某些情况下可以很好地工作,但每当我的对象模型变得有点复杂时,我就开始以我不想不得不的方式担心对象图

相反,这与客户机无关,但它同样适用于JS客户机,我尝试将数据契约类视为完全没有EF映射的纯数据卡车(DTO)。这些类只是我来回传递的文档,如果你愿意的话,就是消息体。它们可能会转换为我的模型上的命令,或者用于填充查询,或者其他什么,但它们本身不是实体

我发现,这大大简化了事情。当您第一次编写一个简单的服务时,它可能感觉像是更多的代码,但在整个生命周期中,它使事情变得更易于维护


作为一个侧重点,你也应该考虑把责任划分得更好一些。web服务类不应该负责直接创建和处理数据上下文,它应该依赖于DAO或存储库接口(或域服务),它可以为您处理所有这些内容(并根据需要应用事务等)。

get方法可能会崩溃

如果此行返回null:

   var emp = results.FirstOrDefault();
然后此行将因空引用异常而崩溃:

   where item2.Employee_ID == emp.Employee_ID

我还将加入一些try-catch块,记录错误。

还有一些改进需要改进

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;
var results = from item in ctx.Employees
              where item.ID == emp.ID
              select item;

var myEmp = results.FirstOrDefault();
您可以这样做:

ctx.Employees.ApplyCurrentValues(emp)

这样做的目的是在图中查找具有相同键的实体(存在,因为您刚刚使用
FirstOrDefault()
检索了它),并使用传入的实体覆盖标量值-这正是您所做的

因此,您的7行变为1,再加上如果您添加任何额外的标量属性,您就不必重构代码。请记住-仅适用于标量属性,而不适用于导航属性

为什么要为主键检索生成查询?只需将谓词用于SingleOrDefault()

与此相反:

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;
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();
其中
WithId
是一个
IQueryable
扩展方法,它根据提供的员工ID过滤查询。这允许从存储库/DAL中分离过滤/业务逻辑。它应该放在你的域模型中,这样你就可以有一个很好的fluent API,通过你的ORM查询你的域实体

通过主键检索实体时,应始终使用
SingleOrDefault()
Single()
,切勿使用
FirstOrDefault()
First()
。如果它是主键-应该只有其中一个,因此如果存在多个异常,则应该抛出异常,
SingleOrDefault()
就是这样做的。正如@Shiraz所提到的,您的
FirstOrDefault()
将使下面的查询崩溃。使用
或default()
时,始终需要进行空检查

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

总的来说,您的代码在功能上没有问题-它只需要细微的改进、空检查和异常处理

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

在进行了我上面提到的更改之后,您的web服务方法应该每个不超过5-7行代码


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

为什么您有一个单独的
AjaxEmployee
类?它是您的
员工
实体的投影吗?单独的类是在发送到javascript时更好地序列化为JSON。由于员工与记录外时间之间存在关系,因此序列化无法根据以下规则正确进行:从不知道
ApplyCurrentValues
+1!ApplyCurrentValues听起来像是安全问题的秘方。这听起来像是击中GitHub的Mass Apply bug。只有一件事您必须访问上下文包装才能使用ApplyCurrentValues进行编码:)