我正在尝试一些查询,以找出获得性能提升的最佳方法。
我知道使用IQueryable比执行Linq to Sql或Linq to Entity数据库查询更好,IEnumerable最适合用于linq到Objects,Linq到xml以及内存处理。
我的WCF服务上有如下的linq查询。当我尝试修改调用它的Controller方法时,我得到以下设计时编译错误:
无法将类型'YeagerTechModel.DropDownLists.ProjectDescription []'隐式转换为'System.Linq.IQueryable'
请注意,ProjectDescription对象定义如下:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
namespace YeagerTechModel.DropDownLists
{
[DataContract]
[Serializable]
public partial class ProjectDescription
{
[DataMember]
public Int16 ProjectID { get; set; }
[DataMember]
public String Description { get; set; }
}
}
这是DB方法调用:
public IQueryable<ProjectDescription> GetProjectDropDownList()
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IQueryable<ProjectDescription> project = DbContext.Projects.Where(w => w.Notes != null).Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
return project;
}
}
catch (Exception ex)
{
throw ex;
}
}
以下是Controller方法中的代码:
IQueryable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
现在,在阅读了IQueryable等性能提升之后的实验之前,从数据库中获取数据的原始方法如下:
public List<ProjectDescription> GetProjectDropDownList()
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
var project = DbContext.Projects.Where(w => w.Notes != null).Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
List<ProjectDescription> myProjects = new List<ProjectDescription>();
myProjects = project.ToList();
return myProjects;
}
}
catch (Exception ex)
{
throw ex;
}
}
Controller中的代码如下:
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
第一个问题是: 许多查询使用var关键字来推断返回的类型。在调用数据库检索记录时使用哪一个? “var”语法或“IQuerable”语法“?
我注意到的第二件事是在Controller端,对于集合,它总是需要一个容易转换为IEnumerable的List对象。
所以,基于这个前提,我认为我的最佳解决方案如下: 对于DB方法调用:
public List<ProjectDescription> GetProjectDropDownList()
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IQueryable<ProjectDescription> project = DbContext.Projects.Where(w => w.Notes != null).Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
List<ProjectDescription> myProjects = new List<ProjectDescription>();
myProjects = project.ToList();
return myProjects;
}
}
catch (Exception ex)
{
throw ex;
}
}
对于Controller中的代码片段,它应如下所示,一切正常:
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
因此,如果IQueryable提供更好的性能(特别是在过滤和支持延迟加载时),为什么不使用最后一个DB方法而不是“var”关键字?
有人可以帮助解释什么是最佳情景吗?
答案 0 :(得分:0)
无论您使用var
还是花时间输入变量的类型都不是问题。你的第二个和第三个例子都编译成完全相同的代码。
然而,你的第一个实现很多比其他两个更好。您的第一个方法返回查询。其他两个返回该查询的结果。
因此,第一个实现允许调用者应用该查询的进一步过滤器/映射/操作,并将它们反映在被调用的数据库查询中,而不是内存中的结果。这也意味着您将延迟实际执行该查询,直到您需要它时,而不是现在。
该实施确实存在缺陷;您是在执行查询之前推迟执行,而是处理底层上下文。您需要将上下文的范围设置为“更高”级别,以确保在查询执行之后它尚未被处置。
至于错误,您没有显示足够的信息来查看问题所在,但您应该努力修复它,而不必在应用程序中而不是在数据库中执行所有数据操作。
旁注:抓住异常只是为了重新抛出它是没有意义的。你没有做任何有效的工作,但清除了堆栈跟踪。如果你与它没有任何关系,就不要在第一时间捕获异常。